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'
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"});
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 {String} btnPosition set the position of the trigger button (left | right) default right
10120 * Create a new ComboBox.
10121 * @param {Object} config Configuration options
10123 Roo.bootstrap.ComboBox = function(config){
10124 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10128 * Fires when the dropdown list is expanded
10129 * @param {Roo.bootstrap.ComboBox} combo This combo box
10134 * Fires when the dropdown list is collapsed
10135 * @param {Roo.bootstrap.ComboBox} combo This combo box
10139 * @event beforeselect
10140 * Fires before a list item is selected. Return false to cancel the selection.
10141 * @param {Roo.bootstrap.ComboBox} combo This combo box
10142 * @param {Roo.data.Record} record The data record returned from the underlying store
10143 * @param {Number} index The index of the selected item in the dropdown list
10145 'beforeselect' : true,
10148 * Fires when a list item is selected
10149 * @param {Roo.bootstrap.ComboBox} combo This combo box
10150 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10151 * @param {Number} index The index of the selected item in the dropdown list
10155 * @event beforequery
10156 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10157 * The event object passed has these properties:
10158 * @param {Roo.bootstrap.ComboBox} combo This combo box
10159 * @param {String} query The query
10160 * @param {Boolean} forceAll true to force "all" query
10161 * @param {Boolean} cancel true to cancel the query
10162 * @param {Object} e The query event object
10164 'beforequery': true,
10167 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10168 * @param {Roo.bootstrap.ComboBox} combo This combo box
10173 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10174 * @param {Roo.bootstrap.ComboBox} combo This combo box
10175 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10180 * Fires when the remove value from the combobox array
10181 * @param {Roo.bootstrap.ComboBox} combo This combo box
10188 this.tickItems = [];
10190 this.selectedIndex = -1;
10191 if(this.mode == 'local'){
10192 if(config.queryDelay === undefined){
10193 this.queryDelay = 10;
10195 if(config.minChars === undefined){
10201 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10204 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10205 * rendering into an Roo.Editor, defaults to false)
10208 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10209 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10212 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10215 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10216 * the dropdown list (defaults to undefined, with no header element)
10220 * @cfg {String/Roo.Template} tpl The template to use to render the output
10224 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10226 listWidth: undefined,
10228 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10229 * mode = 'remote' or 'text' if mode = 'local')
10231 displayField: undefined,
10233 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10234 * mode = 'remote' or 'value' if mode = 'local').
10235 * Note: use of a valueField requires the user make a selection
10236 * in order for a value to be mapped.
10238 valueField: undefined,
10242 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10243 * field's data value (defaults to the underlying DOM element's name)
10245 hiddenName: undefined,
10247 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10251 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10253 selectedClass: 'active',
10256 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10260 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10261 * anchor positions (defaults to 'tl-bl')
10263 listAlign: 'tl-bl?',
10265 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10269 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10270 * query specified by the allQuery config option (defaults to 'query')
10272 triggerAction: 'query',
10274 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10275 * (defaults to 4, does not apply if editable = false)
10279 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10280 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10284 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10285 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10289 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10290 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10294 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10295 * when editable = true (defaults to false)
10297 selectOnFocus:false,
10299 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10301 queryParam: 'query',
10303 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10304 * when mode = 'remote' (defaults to 'Loading...')
10306 loadingText: 'Loading...',
10308 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10312 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10316 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10317 * traditional select (defaults to true)
10321 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10325 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10329 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10330 * listWidth has a higher value)
10334 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10335 * allow the user to set arbitrary text into the field (defaults to false)
10337 forceSelection:false,
10339 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10340 * if typeAhead = true (defaults to 250)
10342 typeAheadDelay : 250,
10344 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10345 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10347 valueNotFoundText : undefined,
10349 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10351 blockFocus : false,
10354 * @cfg {Boolean} disableClear Disable showing of clear button.
10356 disableClear : false,
10358 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10360 alwaysQuery : false,
10363 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10377 btnPosition : 'right',
10378 triggerList : true,
10379 // element that contains real text value.. (when hidden is used..)
10381 getAutoCreate : function()
10388 if(!this.tickable){
10389 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10394 * ComboBox with tickable selections
10397 var align = this.labelAlign || this.parentLabelAlign();
10400 cls : 'form-group roo-combobox-tickable' //input-group
10406 cls : 'tickable-buttons',
10411 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10418 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10425 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10432 Roo.each(buttons.cn, function(c){
10434 c.cls += ' btn-' + _this.size;
10437 if (_this.disabled) {
10448 cls: 'form-hidden-field'
10452 cls: 'select2-choices',
10456 cls: 'select2-search-field',
10468 cls: 'select2-container input-group select2-container-multi',
10473 // cls: 'typeahead typeahead-long dropdown-menu',
10474 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10479 if (align ==='left' && this.fieldLabel.length) {
10481 Roo.log("left and has label");
10487 cls : 'control-label col-sm-' + this.labelWidth,
10488 html : this.fieldLabel
10492 cls : "col-sm-" + (12 - this.labelWidth),
10499 } else if ( this.fieldLabel.length) {
10505 //cls : 'input-group-addon',
10506 html : this.fieldLabel
10516 Roo.log(" no label && no align");
10523 ['xs','sm','md','lg'].map(function(size){
10524 if (settings[size]) {
10525 cfg.cls += ' col-' + size + '-' + settings[size];
10534 initEvents: function()
10538 throw "can not find store for combo";
10540 this.store = Roo.factory(this.store, Roo.data);
10543 this.initTickableEvents();
10547 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10549 if(this.hiddenName){
10551 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10553 this.hiddenField.dom.value =
10554 this.hiddenValue !== undefined ? this.hiddenValue :
10555 this.value !== undefined ? this.value : '';
10557 // prevent input submission
10558 this.el.dom.removeAttribute('name');
10559 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10564 // this.el.dom.setAttribute('autocomplete', 'off');
10567 var cls = 'x-combo-list';
10569 //this.list = new Roo.Layer({
10570 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10576 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10577 _this.list.setWidth(lw);
10580 this.list.on('mouseover', this.onViewOver, this);
10581 this.list.on('mousemove', this.onViewMove, this);
10583 this.list.on('scroll', this.onViewScroll, this);
10586 this.list.swallowEvent('mousewheel');
10587 this.assetHeight = 0;
10590 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10591 this.assetHeight += this.header.getHeight();
10594 this.innerList = this.list.createChild({cls:cls+'-inner'});
10595 this.innerList.on('mouseover', this.onViewOver, this);
10596 this.innerList.on('mousemove', this.onViewMove, this);
10597 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10599 if(this.allowBlank && !this.pageSize && !this.disableClear){
10600 this.footer = this.list.createChild({cls:cls+'-ft'});
10601 this.pageTb = new Roo.Toolbar(this.footer);
10605 this.footer = this.list.createChild({cls:cls+'-ft'});
10606 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10607 {pageSize: this.pageSize});
10611 if (this.pageTb && this.allowBlank && !this.disableClear) {
10613 this.pageTb.add(new Roo.Toolbar.Fill(), {
10614 cls: 'x-btn-icon x-btn-clear',
10616 handler: function()
10619 _this.clearValue();
10620 _this.onSelect(false, -1);
10625 this.assetHeight += this.footer.getHeight();
10630 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10633 this.view = new Roo.View(this.list, this.tpl, {
10634 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10636 //this.view.wrapEl.setDisplayed(false);
10637 this.view.on('click', this.onViewClick, this);
10641 this.store.on('beforeload', this.onBeforeLoad, this);
10642 this.store.on('load', this.onLoad, this);
10643 this.store.on('loadexception', this.onLoadException, this);
10645 if(this.resizable){
10646 this.resizer = new Roo.Resizable(this.list, {
10647 pinned:true, handles:'se'
10649 this.resizer.on('resize', function(r, w, h){
10650 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10651 this.listWidth = w;
10652 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10653 this.restrictHeight();
10655 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10658 if(!this.editable){
10659 this.editable = true;
10660 this.setEditable(false);
10665 if (typeof(this.events.add.listeners) != 'undefined') {
10667 this.addicon = this.wrap.createChild(
10668 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10670 this.addicon.on('click', function(e) {
10671 this.fireEvent('add', this);
10674 if (typeof(this.events.edit.listeners) != 'undefined') {
10676 this.editicon = this.wrap.createChild(
10677 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10678 if (this.addicon) {
10679 this.editicon.setStyle('margin-left', '40px');
10681 this.editicon.on('click', function(e) {
10683 // we fire even if inothing is selected..
10684 this.fireEvent('edit', this, this.lastData );
10690 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10691 "up" : function(e){
10692 this.inKeyMode = true;
10696 "down" : function(e){
10697 if(!this.isExpanded()){
10698 this.onTriggerClick();
10700 this.inKeyMode = true;
10705 "enter" : function(e){
10706 // this.onViewClick();
10710 if(this.fireEvent("specialkey", this, e)){
10711 this.onViewClick(false);
10717 "esc" : function(e){
10721 "tab" : function(e){
10724 if(this.fireEvent("specialkey", this, e)){
10725 this.onViewClick(false);
10733 doRelay : function(foo, bar, hname){
10734 if(hname == 'down' || this.scope.isExpanded()){
10735 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10744 this.queryDelay = Math.max(this.queryDelay || 10,
10745 this.mode == 'local' ? 10 : 250);
10748 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10750 if(this.typeAhead){
10751 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10753 if(this.editable !== false){
10754 this.inputEl().on("keyup", this.onKeyUp, this);
10756 if(this.forceSelection){
10757 this.inputEl().on('blur', this.doForce, this);
10761 this.choices = this.el.select('ul.select2-choices', true).first();
10762 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10766 initTickableEvents: function()
10770 if(this.hiddenName){
10772 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10774 this.hiddenField.dom.value =
10775 this.hiddenValue !== undefined ? this.hiddenValue :
10776 this.value !== undefined ? this.value : '';
10778 // prevent input submission
10779 this.el.dom.removeAttribute('name');
10780 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10785 // this.list = this.el.select('ul.dropdown-menu',true).first();
10787 this.choices = this.el.select('ul.select2-choices', true).first();
10788 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10789 if(this.triggerList){
10790 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10793 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10794 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10796 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10797 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10799 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10800 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10802 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10803 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10804 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10807 this.cancelBtn.hide();
10812 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10813 _this.list.setWidth(lw);
10816 this.list.on('mouseover', this.onViewOver, this);
10817 this.list.on('mousemove', this.onViewMove, this);
10819 this.list.on('scroll', this.onViewScroll, this);
10822 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>';
10825 this.view = new Roo.View(this.list, this.tpl, {
10826 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10829 //this.view.wrapEl.setDisplayed(false);
10830 this.view.on('click', this.onViewClick, this);
10834 this.store.on('beforeload', this.onBeforeLoad, this);
10835 this.store.on('load', this.onLoad, this);
10836 this.store.on('loadexception', this.onLoadException, this);
10838 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10839 // "up" : function(e){
10840 // this.inKeyMode = true;
10841 // this.selectPrev();
10844 // "down" : function(e){
10845 // if(!this.isExpanded()){
10846 // this.onTriggerClick();
10848 // this.inKeyMode = true;
10849 // this.selectNext();
10853 // "enter" : function(e){
10854 //// this.onViewClick();
10856 // this.collapse();
10858 // if(this.fireEvent("specialkey", this, e)){
10859 // this.onViewClick(false);
10865 // "esc" : function(e){
10866 // this.collapse();
10869 // "tab" : function(e){
10870 // this.collapse();
10872 // if(this.fireEvent("specialkey", this, e)){
10873 // this.onViewClick(false);
10881 // doRelay : function(foo, bar, hname){
10882 // if(hname == 'down' || this.scope.isExpanded()){
10883 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10888 // forceKeyDown: true
10892 this.queryDelay = Math.max(this.queryDelay || 10,
10893 this.mode == 'local' ? 10 : 250);
10896 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10898 if(this.typeAhead){
10899 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10903 onDestroy : function(){
10905 this.view.setStore(null);
10906 this.view.el.removeAllListeners();
10907 this.view.el.remove();
10908 this.view.purgeListeners();
10911 this.list.dom.innerHTML = '';
10915 this.store.un('beforeload', this.onBeforeLoad, this);
10916 this.store.un('load', this.onLoad, this);
10917 this.store.un('loadexception', this.onLoadException, this);
10919 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10923 fireKey : function(e){
10924 if(e.isNavKeyPress() && !this.list.isVisible()){
10925 this.fireEvent("specialkey", this, e);
10930 onResize: function(w, h){
10931 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10933 // if(typeof w != 'number'){
10934 // // we do not handle it!?!?
10937 // var tw = this.trigger.getWidth();
10938 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10939 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10941 // this.inputEl().setWidth( this.adjustWidth('input', x));
10943 // //this.trigger.setStyle('left', x+'px');
10945 // if(this.list && this.listWidth === undefined){
10946 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10947 // this.list.setWidth(lw);
10948 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10956 * Allow or prevent the user from directly editing the field text. If false is passed,
10957 * the user will only be able to select from the items defined in the dropdown list. This method
10958 * is the runtime equivalent of setting the 'editable' config option at config time.
10959 * @param {Boolean} value True to allow the user to directly edit the field text
10961 setEditable : function(value){
10962 if(value == this.editable){
10965 this.editable = value;
10967 this.inputEl().dom.setAttribute('readOnly', true);
10968 this.inputEl().on('mousedown', this.onTriggerClick, this);
10969 this.inputEl().addClass('x-combo-noedit');
10971 this.inputEl().dom.setAttribute('readOnly', false);
10972 this.inputEl().un('mousedown', this.onTriggerClick, this);
10973 this.inputEl().removeClass('x-combo-noedit');
10979 onBeforeLoad : function(combo,opts){
10980 if(!this.hasFocus){
10984 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10986 // this.restrictHeight();
10987 this.selectedIndex = -1;
10991 onLoad : function(){
10993 this.hasQuery = false;
10995 if(!this.hasFocus){
10999 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11000 this.loading.hide();
11003 if(this.store.getCount() > 0){
11005 // this.restrictHeight();
11006 if(this.lastQuery == this.allQuery){
11007 if(this.editable && !this.tickable){
11008 this.inputEl().dom.select();
11010 if(!this.selectByValue(this.value, true) && this.autoFocus){
11011 this.select(0, true);
11014 if(this.autoFocus){
11017 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11018 this.taTask.delay(this.typeAheadDelay);
11022 this.onEmptyResults();
11028 onLoadException : function()
11030 this.hasQuery = false;
11032 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11033 this.loading.hide();
11037 Roo.log(this.store.reader.jsonData);
11038 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11040 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11046 onTypeAhead : function(){
11047 if(this.store.getCount() > 0){
11048 var r = this.store.getAt(0);
11049 var newValue = r.data[this.displayField];
11050 var len = newValue.length;
11051 var selStart = this.getRawValue().length;
11053 if(selStart != len){
11054 this.setRawValue(newValue);
11055 this.selectText(selStart, newValue.length);
11061 onSelect : function(record, index){
11063 if(this.fireEvent('beforeselect', this, record, index) !== false){
11065 this.setFromData(index > -1 ? record.data : false);
11068 this.fireEvent('select', this, record, index);
11073 * Returns the currently selected field value or empty string if no value is set.
11074 * @return {String} value The selected value
11076 getValue : function(){
11079 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11082 if(this.valueField){
11083 return typeof this.value != 'undefined' ? this.value : '';
11085 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11090 * Clears any text/value currently set in the field
11092 clearValue : function(){
11093 if(this.hiddenField){
11094 this.hiddenField.dom.value = '';
11097 this.setRawValue('');
11098 this.lastSelectionText = '';
11103 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11104 * will be displayed in the field. If the value does not match the data value of an existing item,
11105 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11106 * Otherwise the field will be blank (although the value will still be set).
11107 * @param {String} value The value to match
11109 setValue : function(v){
11116 if(this.valueField){
11117 var r = this.findRecord(this.valueField, v);
11119 text = r.data[this.displayField];
11120 }else if(this.valueNotFoundText !== undefined){
11121 text = this.valueNotFoundText;
11124 this.lastSelectionText = text;
11125 if(this.hiddenField){
11126 this.hiddenField.dom.value = v;
11128 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11132 * @property {Object} the last set data for the element
11137 * Sets the value of the field based on a object which is related to the record format for the store.
11138 * @param {Object} value the value to set as. or false on reset?
11140 setFromData : function(o){
11143 if(typeof o.display_name !== 'string'){
11144 for(var i=0;i<o.display_name.length;i++){
11145 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11153 var dv = ''; // display value
11154 var vv = ''; // value value..
11156 if (this.displayField) {
11157 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11159 // this is an error condition!!!
11160 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11163 if(this.valueField){
11164 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11167 if(this.hiddenField){
11168 this.hiddenField.dom.value = vv;
11170 this.lastSelectionText = dv;
11171 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11175 // no hidden field.. - we store the value in 'value', but still display
11176 // display field!!!!
11177 this.lastSelectionText = dv;
11178 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11184 reset : function(){
11185 // overridden so that last data is reset..
11186 this.setValue(this.originalValue);
11187 this.clearInvalid();
11188 this.lastData = false;
11190 this.view.clearSelections();
11194 findRecord : function(prop, value){
11196 if(this.store.getCount() > 0){
11197 this.store.each(function(r){
11198 if(r.data[prop] == value){
11208 getName: function()
11210 // returns hidden if it's set..
11211 if (!this.rendered) {return ''};
11212 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11216 onViewMove : function(e, t){
11217 this.inKeyMode = false;
11221 onViewOver : function(e, t){
11222 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11225 var item = this.view.findItemFromChild(t);
11228 var index = this.view.indexOf(item);
11229 this.select(index, false);
11234 onViewClick : function(view, doFocus, el, e)
11236 var index = this.view.getSelectedIndexes()[0];
11238 var r = this.store.getAt(index);
11242 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11249 Roo.each(this.tickItems, function(v,k){
11251 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11252 _this.tickItems.splice(k, 1);
11262 this.tickItems.push(r.data);
11267 this.onSelect(r, index);
11269 if(doFocus !== false && !this.blockFocus){
11270 this.inputEl().focus();
11275 restrictHeight : function(){
11276 //this.innerList.dom.style.height = '';
11277 //var inner = this.innerList.dom;
11278 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11279 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11280 //this.list.beginUpdate();
11281 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11282 this.list.alignTo(this.inputEl(), this.listAlign);
11283 this.list.alignTo(this.inputEl(), this.listAlign);
11284 //this.list.endUpdate();
11288 onEmptyResults : function(){
11293 * Returns true if the dropdown list is expanded, else false.
11295 isExpanded : function(){
11296 return this.list.isVisible();
11300 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11301 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11302 * @param {String} value The data value of the item to select
11303 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11304 * selected item if it is not currently in view (defaults to true)
11305 * @return {Boolean} True if the value matched an item in the list, else false
11307 selectByValue : function(v, scrollIntoView){
11308 if(v !== undefined && v !== null){
11309 var r = this.findRecord(this.valueField || this.displayField, v);
11311 this.select(this.store.indexOf(r), scrollIntoView);
11319 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11320 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11321 * @param {Number} index The zero-based index of the list item to select
11322 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11323 * selected item if it is not currently in view (defaults to true)
11325 select : function(index, scrollIntoView){
11326 this.selectedIndex = index;
11327 this.view.select(index);
11328 if(scrollIntoView !== false){
11329 var el = this.view.getNode(index);
11330 if(el && !this.multiple && !this.tickable){
11331 this.list.scrollChildIntoView(el, false);
11337 selectNext : function(){
11338 var ct = this.store.getCount();
11340 if(this.selectedIndex == -1){
11342 }else if(this.selectedIndex < ct-1){
11343 this.select(this.selectedIndex+1);
11349 selectPrev : function(){
11350 var ct = this.store.getCount();
11352 if(this.selectedIndex == -1){
11354 }else if(this.selectedIndex != 0){
11355 this.select(this.selectedIndex-1);
11361 onKeyUp : function(e){
11362 if(this.editable !== false && !e.isSpecialKey()){
11363 this.lastKey = e.getKey();
11364 this.dqTask.delay(this.queryDelay);
11369 validateBlur : function(){
11370 return !this.list || !this.list.isVisible();
11374 initQuery : function(){
11375 this.doQuery(this.getRawValue());
11379 doForce : function(){
11380 if(this.inputEl().dom.value.length > 0){
11381 this.inputEl().dom.value =
11382 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11388 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11389 * query allowing the query action to be canceled if needed.
11390 * @param {String} query The SQL query to execute
11391 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11392 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11393 * saved in the current store (defaults to false)
11395 doQuery : function(q, forceAll){
11397 if(q === undefined || q === null){
11402 forceAll: forceAll,
11406 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11411 forceAll = qe.forceAll;
11412 if(forceAll === true || (q.length >= this.minChars)){
11414 this.hasQuery = true;
11416 if(this.lastQuery != q || this.alwaysQuery){
11417 this.lastQuery = q;
11418 if(this.mode == 'local'){
11419 this.selectedIndex = -1;
11421 this.store.clearFilter();
11423 this.store.filter(this.displayField, q);
11427 this.store.baseParams[this.queryParam] = q;
11429 var options = {params : this.getParams(q)};
11432 options.add = true;
11433 options.params.start = this.page * this.pageSize;
11436 this.store.load(options);
11438 * this code will make the page width larger, at the beginning, the list not align correctly,
11439 * we should expand the list on onLoad
11440 * so command out it
11445 this.selectedIndex = -1;
11450 this.loadNext = false;
11454 getParams : function(q){
11456 //p[this.queryParam] = q;
11460 p.limit = this.pageSize;
11466 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11468 collapse : function(){
11469 if(!this.isExpanded()){
11473 this.hasFocus = false;
11479 this.cancelBtn.hide();
11480 this.trigger.show();
11483 Roo.get(document).un('mousedown', this.collapseIf, this);
11484 Roo.get(document).un('mousewheel', this.collapseIf, this);
11485 if (!this.editable) {
11486 Roo.get(document).un('keydown', this.listKeyPress, this);
11488 this.fireEvent('collapse', this);
11492 collapseIf : function(e){
11493 var in_combo = e.within(this.el);
11494 var in_list = e.within(this.list);
11495 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11497 if (in_combo || in_list || is_list) {
11498 //e.stopPropagation();
11503 this.onTickableFooterButtonClick(e, false, false);
11511 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11513 expand : function(){
11515 if(this.isExpanded() || !this.hasFocus){
11522 this.restrictHeight();
11526 this.tickItems = Roo.apply([], this.item);
11529 this.cancelBtn.show();
11530 this.trigger.hide();
11534 Roo.get(document).on('mousedown', this.collapseIf, this);
11535 Roo.get(document).on('mousewheel', this.collapseIf, this);
11536 if (!this.editable) {
11537 Roo.get(document).on('keydown', this.listKeyPress, this);
11540 this.fireEvent('expand', this);
11544 // Implements the default empty TriggerField.onTriggerClick function
11545 onTriggerClick : function(e)
11547 Roo.log('trigger click');
11549 if(this.disabled || !this.triggerList){
11554 this.loadNext = false;
11556 if(this.isExpanded()){
11558 if (!this.blockFocus) {
11559 this.inputEl().focus();
11563 this.hasFocus = true;
11564 if(this.triggerAction == 'all') {
11565 this.doQuery(this.allQuery, true);
11567 this.doQuery(this.getRawValue());
11569 if (!this.blockFocus) {
11570 this.inputEl().focus();
11575 onTickableTriggerClick : function(e)
11582 this.loadNext = false;
11583 this.hasFocus = true;
11585 if(this.triggerAction == 'all') {
11586 this.doQuery(this.allQuery, true);
11588 this.doQuery(this.getRawValue());
11592 onSearchFieldClick : function(e)
11594 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11599 this.loadNext = false;
11600 this.hasFocus = true;
11602 if(this.triggerAction == 'all') {
11603 this.doQuery(this.allQuery, true);
11605 this.doQuery(this.getRawValue());
11609 listKeyPress : function(e)
11611 //Roo.log('listkeypress');
11612 // scroll to first matching element based on key pres..
11613 if (e.isSpecialKey()) {
11616 var k = String.fromCharCode(e.getKey()).toUpperCase();
11619 var csel = this.view.getSelectedNodes();
11620 var cselitem = false;
11622 var ix = this.view.indexOf(csel[0]);
11623 cselitem = this.store.getAt(ix);
11624 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11630 this.store.each(function(v) {
11632 // start at existing selection.
11633 if (cselitem.id == v.id) {
11639 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11640 match = this.store.indexOf(v);
11646 if (match === false) {
11647 return true; // no more action?
11650 this.view.select(match);
11651 var sn = Roo.get(this.view.getSelectedNodes()[0])
11652 //sn.scrollIntoView(sn.dom.parentNode, false);
11655 onViewScroll : function(e, t){
11657 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11661 this.hasQuery = true;
11663 this.loading = this.list.select('.loading', true).first();
11665 if(this.loading === null){
11666 this.list.createChild({
11668 cls: 'loading select2-more-results select2-active',
11669 html: 'Loading more results...'
11672 this.loading = this.list.select('.loading', true).first();
11674 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11676 this.loading.hide();
11679 this.loading.show();
11684 this.loadNext = true;
11686 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11691 addItem : function(o)
11693 var dv = ''; // display value
11695 if (this.displayField) {
11696 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11698 // this is an error condition!!!
11699 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11706 var choice = this.choices.createChild({
11708 cls: 'select2-search-choice',
11717 cls: 'select2-search-choice-close',
11722 }, this.searchField);
11724 var close = choice.select('a.select2-search-choice-close', true).first()
11726 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11734 this.inputEl().dom.value = '';
11738 onRemoveItem : function(e, _self, o)
11740 e.preventDefault();
11741 var index = this.item.indexOf(o.data) * 1;
11744 Roo.log('not this item?!');
11748 this.item.splice(index, 1);
11753 this.fireEvent('remove', this, e);
11757 syncValue : function()
11759 if(!this.item.length){
11766 Roo.each(this.item, function(i){
11767 if(_this.valueField){
11768 value.push(i[_this.valueField]);
11775 this.value = value.join(',');
11777 if(this.hiddenField){
11778 this.hiddenField.dom.value = this.value;
11782 clearItem : function()
11784 if(!this.multiple){
11790 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11797 inputEl: function ()
11800 return this.searchField;
11802 return this.el.select('input.form-control',true).first();
11806 onTickableFooterButtonClick : function(e, btn, el)
11808 e.preventDefault();
11810 if(btn && btn.name == 'cancel'){
11811 this.tickItems = Roo.apply([], this.item);
11820 Roo.each(this.tickItems, function(o){
11831 * @cfg {Boolean} grow
11835 * @cfg {Number} growMin
11839 * @cfg {Number} growMax
11849 * Ext JS Library 1.1.1
11850 * Copyright(c) 2006-2007, Ext JS, LLC.
11852 * Originally Released Under LGPL - original licence link has changed is not relivant.
11855 * <script type="text/javascript">
11860 * @extends Roo.util.Observable
11861 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11862 * This class also supports single and multi selection modes. <br>
11863 * Create a data model bound view:
11865 var store = new Roo.data.Store(...);
11867 var view = new Roo.View({
11869 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11871 singleSelect: true,
11872 selectedClass: "ydataview-selected",
11876 // listen for node click?
11877 view.on("click", function(vw, index, node, e){
11878 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11882 dataModel.load("foobar.xml");
11884 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11886 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11887 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11889 * Note: old style constructor is still suported (container, template, config)
11892 * Create a new View
11893 * @param {Object} config The config object
11896 Roo.View = function(config, depreciated_tpl, depreciated_config){
11898 this.parent = false;
11900 if (typeof(depreciated_tpl) == 'undefined') {
11901 // new way.. - universal constructor.
11902 Roo.apply(this, config);
11903 this.el = Roo.get(this.el);
11906 this.el = Roo.get(config);
11907 this.tpl = depreciated_tpl;
11908 Roo.apply(this, depreciated_config);
11910 this.wrapEl = this.el.wrap().wrap();
11911 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11914 if(typeof(this.tpl) == "string"){
11915 this.tpl = new Roo.Template(this.tpl);
11917 // support xtype ctors..
11918 this.tpl = new Roo.factory(this.tpl, Roo);
11922 this.tpl.compile();
11927 * @event beforeclick
11928 * Fires before a click is processed. Returns false to cancel the default action.
11929 * @param {Roo.View} this
11930 * @param {Number} index The index of the target node
11931 * @param {HTMLElement} node The target node
11932 * @param {Roo.EventObject} e The raw event object
11934 "beforeclick" : true,
11937 * Fires when a template node is clicked.
11938 * @param {Roo.View} this
11939 * @param {Number} index The index of the target node
11940 * @param {HTMLElement} node The target node
11941 * @param {Roo.EventObject} e The raw event object
11946 * Fires when a template node is double clicked.
11947 * @param {Roo.View} this
11948 * @param {Number} index The index of the target node
11949 * @param {HTMLElement} node The target node
11950 * @param {Roo.EventObject} e The raw event object
11954 * @event contextmenu
11955 * Fires when a template node is right clicked.
11956 * @param {Roo.View} this
11957 * @param {Number} index The index of the target node
11958 * @param {HTMLElement} node The target node
11959 * @param {Roo.EventObject} e The raw event object
11961 "contextmenu" : true,
11963 * @event selectionchange
11964 * Fires when the selected nodes change.
11965 * @param {Roo.View} this
11966 * @param {Array} selections Array of the selected nodes
11968 "selectionchange" : true,
11971 * @event beforeselect
11972 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11973 * @param {Roo.View} this
11974 * @param {HTMLElement} node The node to be selected
11975 * @param {Array} selections Array of currently selected nodes
11977 "beforeselect" : true,
11979 * @event preparedata
11980 * Fires on every row to render, to allow you to change the data.
11981 * @param {Roo.View} this
11982 * @param {Object} data to be rendered (change this)
11984 "preparedata" : true
11992 "click": this.onClick,
11993 "dblclick": this.onDblClick,
11994 "contextmenu": this.onContextMenu,
11998 this.selections = [];
12000 this.cmp = new Roo.CompositeElementLite([]);
12002 this.store = Roo.factory(this.store, Roo.data);
12003 this.setStore(this.store, true);
12006 if ( this.footer && this.footer.xtype) {
12008 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12010 this.footer.dataSource = this.store
12011 this.footer.container = fctr;
12012 this.footer = Roo.factory(this.footer, Roo);
12013 fctr.insertFirst(this.el);
12015 // this is a bit insane - as the paging toolbar seems to detach the el..
12016 // dom.parentNode.parentNode.parentNode
12017 // they get detached?
12021 Roo.View.superclass.constructor.call(this);
12026 Roo.extend(Roo.View, Roo.util.Observable, {
12029 * @cfg {Roo.data.Store} store Data store to load data from.
12034 * @cfg {String|Roo.Element} el The container element.
12039 * @cfg {String|Roo.Template} tpl The template used by this View
12043 * @cfg {String} dataName the named area of the template to use as the data area
12044 * Works with domtemplates roo-name="name"
12048 * @cfg {String} selectedClass The css class to add to selected nodes
12050 selectedClass : "x-view-selected",
12052 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12057 * @cfg {String} text to display on mask (default Loading)
12061 * @cfg {Boolean} multiSelect Allow multiple selection
12063 multiSelect : false,
12065 * @cfg {Boolean} singleSelect Allow single selection
12067 singleSelect: false,
12070 * @cfg {Boolean} toggleSelect - selecting
12072 toggleSelect : false,
12075 * @cfg {Boolean} tickable - selecting
12080 * Returns the element this view is bound to.
12081 * @return {Roo.Element}
12083 getEl : function(){
12084 return this.wrapEl;
12090 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12092 refresh : function(){
12093 Roo.log('refresh');
12096 // if we are using something like 'domtemplate', then
12097 // the what gets used is:
12098 // t.applySubtemplate(NAME, data, wrapping data..)
12099 // the outer template then get' applied with
12100 // the store 'extra data'
12101 // and the body get's added to the
12102 // roo-name="data" node?
12103 // <span class='roo-tpl-{name}'></span> ?????
12107 this.clearSelections();
12108 this.el.update("");
12110 var records = this.store.getRange();
12111 if(records.length < 1) {
12113 // is this valid?? = should it render a template??
12115 this.el.update(this.emptyText);
12119 if (this.dataName) {
12120 this.el.update(t.apply(this.store.meta)); //????
12121 el = this.el.child('.roo-tpl-' + this.dataName);
12124 for(var i = 0, len = records.length; i < len; i++){
12125 var data = this.prepareData(records[i].data, i, records[i]);
12126 this.fireEvent("preparedata", this, data, i, records[i]);
12128 var d = Roo.apply({}, data);
12131 Roo.apply(d, {'roo-id' : Roo.id()});
12135 Roo.each(this.parent.item, function(item){
12136 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12139 Roo.apply(d, {'roo-data-checked' : 'checked'});
12143 html[html.length] = Roo.util.Format.trim(
12145 t.applySubtemplate(this.dataName, d, this.store.meta) :
12152 el.update(html.join(""));
12153 this.nodes = el.dom.childNodes;
12154 this.updateIndexes(0);
12159 * Function to override to reformat the data that is sent to
12160 * the template for each node.
12161 * DEPRICATED - use the preparedata event handler.
12162 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12163 * a JSON object for an UpdateManager bound view).
12165 prepareData : function(data, index, record)
12167 this.fireEvent("preparedata", this, data, index, record);
12171 onUpdate : function(ds, record){
12172 Roo.log('on update');
12173 this.clearSelections();
12174 var index = this.store.indexOf(record);
12175 var n = this.nodes[index];
12176 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12177 n.parentNode.removeChild(n);
12178 this.updateIndexes(index, index);
12184 onAdd : function(ds, records, index)
12186 Roo.log(['on Add', ds, records, index] );
12187 this.clearSelections();
12188 if(this.nodes.length == 0){
12192 var n = this.nodes[index];
12193 for(var i = 0, len = records.length; i < len; i++){
12194 var d = this.prepareData(records[i].data, i, records[i]);
12196 this.tpl.insertBefore(n, d);
12199 this.tpl.append(this.el, d);
12202 this.updateIndexes(index);
12205 onRemove : function(ds, record, index){
12206 Roo.log('onRemove');
12207 this.clearSelections();
12208 var el = this.dataName ?
12209 this.el.child('.roo-tpl-' + this.dataName) :
12212 el.dom.removeChild(this.nodes[index]);
12213 this.updateIndexes(index);
12217 * Refresh an individual node.
12218 * @param {Number} index
12220 refreshNode : function(index){
12221 this.onUpdate(this.store, this.store.getAt(index));
12224 updateIndexes : function(startIndex, endIndex){
12225 var ns = this.nodes;
12226 startIndex = startIndex || 0;
12227 endIndex = endIndex || ns.length - 1;
12228 for(var i = startIndex; i <= endIndex; i++){
12229 ns[i].nodeIndex = i;
12234 * Changes the data store this view uses and refresh the view.
12235 * @param {Store} store
12237 setStore : function(store, initial){
12238 if(!initial && this.store){
12239 this.store.un("datachanged", this.refresh);
12240 this.store.un("add", this.onAdd);
12241 this.store.un("remove", this.onRemove);
12242 this.store.un("update", this.onUpdate);
12243 this.store.un("clear", this.refresh);
12244 this.store.un("beforeload", this.onBeforeLoad);
12245 this.store.un("load", this.onLoad);
12246 this.store.un("loadexception", this.onLoad);
12250 store.on("datachanged", this.refresh, this);
12251 store.on("add", this.onAdd, this);
12252 store.on("remove", this.onRemove, this);
12253 store.on("update", this.onUpdate, this);
12254 store.on("clear", this.refresh, this);
12255 store.on("beforeload", this.onBeforeLoad, this);
12256 store.on("load", this.onLoad, this);
12257 store.on("loadexception", this.onLoad, this);
12265 * onbeforeLoad - masks the loading area.
12268 onBeforeLoad : function(store,opts)
12270 Roo.log('onBeforeLoad');
12272 this.el.update("");
12274 this.el.mask(this.mask ? this.mask : "Loading" );
12276 onLoad : function ()
12283 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12284 * @param {HTMLElement} node
12285 * @return {HTMLElement} The template node
12287 findItemFromChild : function(node){
12288 var el = this.dataName ?
12289 this.el.child('.roo-tpl-' + this.dataName,true) :
12292 if(!node || node.parentNode == el){
12295 var p = node.parentNode;
12296 while(p && p != el){
12297 if(p.parentNode == el){
12306 onClick : function(e){
12307 var item = this.findItemFromChild(e.getTarget());
12309 var index = this.indexOf(item);
12310 if(this.onItemClick(item, index, e) !== false){
12311 this.fireEvent("click", this, index, item, e);
12314 this.clearSelections();
12319 onContextMenu : function(e){
12320 var item = this.findItemFromChild(e.getTarget());
12322 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12327 onDblClick : function(e){
12328 var item = this.findItemFromChild(e.getTarget());
12330 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12334 onItemClick : function(item, index, e)
12336 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12339 if (this.toggleSelect) {
12340 var m = this.isSelected(item) ? 'unselect' : 'select';
12343 _t[m](item, true, false);
12346 if(this.multiSelect || this.singleSelect){
12347 if(this.multiSelect && e.shiftKey && this.lastSelection){
12348 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12350 this.select(item, this.multiSelect && e.ctrlKey);
12351 this.lastSelection = item;
12354 if(!this.tickable){
12355 e.preventDefault();
12363 * Get the number of selected nodes.
12366 getSelectionCount : function(){
12367 return this.selections.length;
12371 * Get the currently selected nodes.
12372 * @return {Array} An array of HTMLElements
12374 getSelectedNodes : function(){
12375 return this.selections;
12379 * Get the indexes of the selected nodes.
12382 getSelectedIndexes : function(){
12383 var indexes = [], s = this.selections;
12384 for(var i = 0, len = s.length; i < len; i++){
12385 indexes.push(s[i].nodeIndex);
12391 * Clear all selections
12392 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12394 clearSelections : function(suppressEvent){
12395 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12396 this.cmp.elements = this.selections;
12397 this.cmp.removeClass(this.selectedClass);
12398 this.selections = [];
12399 if(!suppressEvent){
12400 this.fireEvent("selectionchange", this, this.selections);
12406 * Returns true if the passed node is selected
12407 * @param {HTMLElement/Number} node The node or node index
12408 * @return {Boolean}
12410 isSelected : function(node){
12411 var s = this.selections;
12415 node = this.getNode(node);
12416 return s.indexOf(node) !== -1;
12421 * @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
12422 * @param {Boolean} keepExisting (optional) true to keep existing selections
12423 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12425 select : function(nodeInfo, keepExisting, suppressEvent){
12426 if(nodeInfo instanceof Array){
12428 this.clearSelections(true);
12430 for(var i = 0, len = nodeInfo.length; i < len; i++){
12431 this.select(nodeInfo[i], true, true);
12435 var node = this.getNode(nodeInfo);
12436 if(!node || this.isSelected(node)){
12437 return; // already selected.
12440 this.clearSelections(true);
12442 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12443 Roo.fly(node).addClass(this.selectedClass);
12444 this.selections.push(node);
12445 if(!suppressEvent){
12446 this.fireEvent("selectionchange", this, this.selections);
12454 * @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
12455 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12456 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12458 unselect : function(nodeInfo, keepExisting, suppressEvent)
12460 if(nodeInfo instanceof Array){
12461 Roo.each(this.selections, function(s) {
12462 this.unselect(s, nodeInfo);
12466 var node = this.getNode(nodeInfo);
12467 if(!node || !this.isSelected(node)){
12468 Roo.log("not selected");
12469 return; // not selected.
12473 Roo.each(this.selections, function(s) {
12475 Roo.fly(node).removeClass(this.selectedClass);
12482 this.selections= ns;
12483 this.fireEvent("selectionchange", this, this.selections);
12487 * Gets a template node.
12488 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12489 * @return {HTMLElement} The node or null if it wasn't found
12491 getNode : function(nodeInfo){
12492 if(typeof nodeInfo == "string"){
12493 return document.getElementById(nodeInfo);
12494 }else if(typeof nodeInfo == "number"){
12495 return this.nodes[nodeInfo];
12501 * Gets a range template nodes.
12502 * @param {Number} startIndex
12503 * @param {Number} endIndex
12504 * @return {Array} An array of nodes
12506 getNodes : function(start, end){
12507 var ns = this.nodes;
12508 start = start || 0;
12509 end = typeof end == "undefined" ? ns.length - 1 : end;
12512 for(var i = start; i <= end; i++){
12516 for(var i = start; i >= end; i--){
12524 * Finds the index of the passed node
12525 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12526 * @return {Number} The index of the node or -1
12528 indexOf : function(node){
12529 node = this.getNode(node);
12530 if(typeof node.nodeIndex == "number"){
12531 return node.nodeIndex;
12533 var ns = this.nodes;
12534 for(var i = 0, len = ns.length; i < len; i++){
12545 * based on jquery fullcalendar
12549 Roo.bootstrap = Roo.bootstrap || {};
12551 * @class Roo.bootstrap.Calendar
12552 * @extends Roo.bootstrap.Component
12553 * Bootstrap Calendar class
12554 * @cfg {Boolean} loadMask (true|false) default false
12555 * @cfg {Object} header generate the user specific header of the calendar, default false
12558 * Create a new Container
12559 * @param {Object} config The config object
12564 Roo.bootstrap.Calendar = function(config){
12565 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12569 * Fires when a date is selected
12570 * @param {DatePicker} this
12571 * @param {Date} date The selected date
12575 * @event monthchange
12576 * Fires when the displayed month changes
12577 * @param {DatePicker} this
12578 * @param {Date} date The selected month
12580 'monthchange': true,
12582 * @event evententer
12583 * Fires when mouse over an event
12584 * @param {Calendar} this
12585 * @param {event} Event
12587 'evententer': true,
12589 * @event eventleave
12590 * Fires when the mouse leaves an
12591 * @param {Calendar} this
12594 'eventleave': true,
12596 * @event eventclick
12597 * Fires when the mouse click an
12598 * @param {Calendar} this
12607 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12610 * @cfg {Number} startDay
12611 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12619 getAutoCreate : function(){
12622 var fc_button = function(name, corner, style, content ) {
12623 return Roo.apply({},{
12625 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12627 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12630 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12641 style : 'width:100%',
12648 cls : 'fc-header-left',
12650 fc_button('prev', 'left', 'arrow', '‹' ),
12651 fc_button('next', 'right', 'arrow', '›' ),
12652 { tag: 'span', cls: 'fc-header-space' },
12653 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12661 cls : 'fc-header-center',
12665 cls: 'fc-header-title',
12668 html : 'month / year'
12676 cls : 'fc-header-right',
12678 /* fc_button('month', 'left', '', 'month' ),
12679 fc_button('week', '', '', 'week' ),
12680 fc_button('day', 'right', '', 'day' )
12692 header = this.header;
12695 var cal_heads = function() {
12697 // fixme - handle this.
12699 for (var i =0; i < Date.dayNames.length; i++) {
12700 var d = Date.dayNames[i];
12703 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12704 html : d.substring(0,3)
12708 ret[0].cls += ' fc-first';
12709 ret[6].cls += ' fc-last';
12712 var cal_cell = function(n) {
12715 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12720 cls: 'fc-day-number',
12724 cls: 'fc-day-content',
12728 style: 'position: relative;' // height: 17px;
12740 var cal_rows = function() {
12743 for (var r = 0; r < 6; r++) {
12750 for (var i =0; i < Date.dayNames.length; i++) {
12751 var d = Date.dayNames[i];
12752 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12755 row.cn[0].cls+=' fc-first';
12756 row.cn[0].cn[0].style = 'min-height:90px';
12757 row.cn[6].cls+=' fc-last';
12761 ret[0].cls += ' fc-first';
12762 ret[4].cls += ' fc-prev-last';
12763 ret[5].cls += ' fc-last';
12770 cls: 'fc-border-separate',
12771 style : 'width:100%',
12779 cls : 'fc-first fc-last',
12797 cls : 'fc-content',
12798 style : "position: relative;",
12801 cls : 'fc-view fc-view-month fc-grid',
12802 style : 'position: relative',
12803 unselectable : 'on',
12806 cls : 'fc-event-container',
12807 style : 'position:absolute;z-index:8;top:0;left:0;'
12825 initEvents : function()
12828 throw "can not find store for calendar";
12834 style: "text-align:center",
12838 style: "background-color:white;width:50%;margin:250 auto",
12842 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12853 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12855 var size = this.el.select('.fc-content', true).first().getSize();
12856 this.maskEl.setSize(size.width, size.height);
12857 this.maskEl.enableDisplayMode("block");
12858 if(!this.loadMask){
12859 this.maskEl.hide();
12862 this.store = Roo.factory(this.store, Roo.data);
12863 this.store.on('load', this.onLoad, this);
12864 this.store.on('beforeload', this.onBeforeLoad, this);
12868 this.cells = this.el.select('.fc-day',true);
12869 //Roo.log(this.cells);
12870 this.textNodes = this.el.query('.fc-day-number');
12871 this.cells.addClassOnOver('fc-state-hover');
12873 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12874 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12875 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12876 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12878 this.on('monthchange', this.onMonthChange, this);
12880 this.update(new Date().clearTime());
12883 resize : function() {
12884 var sz = this.el.getSize();
12886 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12887 this.el.select('.fc-day-content div',true).setHeight(34);
12892 showPrevMonth : function(e){
12893 this.update(this.activeDate.add("mo", -1));
12895 showToday : function(e){
12896 this.update(new Date().clearTime());
12899 showNextMonth : function(e){
12900 this.update(this.activeDate.add("mo", 1));
12904 showPrevYear : function(){
12905 this.update(this.activeDate.add("y", -1));
12909 showNextYear : function(){
12910 this.update(this.activeDate.add("y", 1));
12915 update : function(date)
12917 var vd = this.activeDate;
12918 this.activeDate = date;
12919 // if(vd && this.el){
12920 // var t = date.getTime();
12921 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12922 // Roo.log('using add remove');
12924 // this.fireEvent('monthchange', this, date);
12926 // this.cells.removeClass("fc-state-highlight");
12927 // this.cells.each(function(c){
12928 // if(c.dateValue == t){
12929 // c.addClass("fc-state-highlight");
12930 // setTimeout(function(){
12931 // try{c.dom.firstChild.focus();}catch(e){}
12941 var days = date.getDaysInMonth();
12943 var firstOfMonth = date.getFirstDateOfMonth();
12944 var startingPos = firstOfMonth.getDay()-this.startDay;
12946 if(startingPos < this.startDay){
12950 var pm = date.add(Date.MONTH, -1);
12951 var prevStart = pm.getDaysInMonth()-startingPos;
12953 this.cells = this.el.select('.fc-day',true);
12954 this.textNodes = this.el.query('.fc-day-number');
12955 this.cells.addClassOnOver('fc-state-hover');
12957 var cells = this.cells.elements;
12958 var textEls = this.textNodes;
12960 Roo.each(cells, function(cell){
12961 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12964 days += startingPos;
12966 // convert everything to numbers so it's fast
12967 var day = 86400000;
12968 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12971 //Roo.log(prevStart);
12973 var today = new Date().clearTime().getTime();
12974 var sel = date.clearTime().getTime();
12975 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12976 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12977 var ddMatch = this.disabledDatesRE;
12978 var ddText = this.disabledDatesText;
12979 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12980 var ddaysText = this.disabledDaysText;
12981 var format = this.format;
12983 var setCellClass = function(cal, cell){
12987 //Roo.log('set Cell Class');
12989 var t = d.getTime();
12993 cell.dateValue = t;
12995 cell.className += " fc-today";
12996 cell.className += " fc-state-highlight";
12997 cell.title = cal.todayText;
13000 // disable highlight in other month..
13001 //cell.className += " fc-state-highlight";
13006 cell.className = " fc-state-disabled";
13007 cell.title = cal.minText;
13011 cell.className = " fc-state-disabled";
13012 cell.title = cal.maxText;
13016 if(ddays.indexOf(d.getDay()) != -1){
13017 cell.title = ddaysText;
13018 cell.className = " fc-state-disabled";
13021 if(ddMatch && format){
13022 var fvalue = d.dateFormat(format);
13023 if(ddMatch.test(fvalue)){
13024 cell.title = ddText.replace("%0", fvalue);
13025 cell.className = " fc-state-disabled";
13029 if (!cell.initialClassName) {
13030 cell.initialClassName = cell.dom.className;
13033 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13038 for(; i < startingPos; i++) {
13039 textEls[i].innerHTML = (++prevStart);
13040 d.setDate(d.getDate()+1);
13042 cells[i].className = "fc-past fc-other-month";
13043 setCellClass(this, cells[i]);
13048 for(; i < days; i++){
13049 intDay = i - startingPos + 1;
13050 textEls[i].innerHTML = (intDay);
13051 d.setDate(d.getDate()+1);
13053 cells[i].className = ''; // "x-date-active";
13054 setCellClass(this, cells[i]);
13058 for(; i < 42; i++) {
13059 textEls[i].innerHTML = (++extraDays);
13060 d.setDate(d.getDate()+1);
13062 cells[i].className = "fc-future fc-other-month";
13063 setCellClass(this, cells[i]);
13066 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13068 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13070 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13071 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13073 if(totalRows != 6){
13074 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13075 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13078 this.fireEvent('monthchange', this, date);
13082 if(!this.internalRender){
13083 var main = this.el.dom.firstChild;
13084 var w = main.offsetWidth;
13085 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13086 Roo.fly(main).setWidth(w);
13087 this.internalRender = true;
13088 // opera does not respect the auto grow header center column
13089 // then, after it gets a width opera refuses to recalculate
13090 // without a second pass
13091 if(Roo.isOpera && !this.secondPass){
13092 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13093 this.secondPass = true;
13094 this.update.defer(10, this, [date]);
13101 findCell : function(dt) {
13102 dt = dt.clearTime().getTime();
13104 this.cells.each(function(c){
13105 //Roo.log("check " +c.dateValue + '?=' + dt);
13106 if(c.dateValue == dt){
13116 findCells : function(ev) {
13117 var s = ev.start.clone().clearTime().getTime();
13119 var e= ev.end.clone().clearTime().getTime();
13122 this.cells.each(function(c){
13123 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13125 if(c.dateValue > e){
13128 if(c.dateValue < s){
13137 // findBestRow: function(cells)
13141 // for (var i =0 ; i < cells.length;i++) {
13142 // ret = Math.max(cells[i].rows || 0,ret);
13149 addItem : function(ev)
13151 // look for vertical location slot in
13152 var cells = this.findCells(ev);
13154 // ev.row = this.findBestRow(cells);
13156 // work out the location.
13160 for(var i =0; i < cells.length; i++) {
13162 cells[i].row = cells[0].row;
13165 cells[i].row = cells[i].row + 1;
13175 if (crow.start.getY() == cells[i].getY()) {
13177 crow.end = cells[i];
13194 cells[0].events.push(ev);
13196 this.calevents.push(ev);
13199 clearEvents: function() {
13201 if(!this.calevents){
13205 Roo.each(this.cells.elements, function(c){
13211 Roo.each(this.calevents, function(e) {
13212 Roo.each(e.els, function(el) {
13213 el.un('mouseenter' ,this.onEventEnter, this);
13214 el.un('mouseleave' ,this.onEventLeave, this);
13219 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13225 renderEvents: function()
13229 this.cells.each(function(c) {
13238 if(c.row != c.events.length){
13239 r = 4 - (4 - (c.row - c.events.length));
13242 c.events = ev.slice(0, r);
13243 c.more = ev.slice(r);
13245 if(c.more.length && c.more.length == 1){
13246 c.events.push(c.more.pop());
13249 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13253 this.cells.each(function(c) {
13255 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13258 for (var e = 0; e < c.events.length; e++){
13259 var ev = c.events[e];
13260 var rows = ev.rows;
13262 for(var i = 0; i < rows.length; i++) {
13264 // how many rows should it span..
13267 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13268 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13270 unselectable : "on",
13273 cls: 'fc-event-inner',
13277 // cls: 'fc-event-time',
13278 // html : cells.length > 1 ? '' : ev.time
13282 cls: 'fc-event-title',
13283 html : String.format('{0}', ev.title)
13290 cls: 'ui-resizable-handle ui-resizable-e',
13291 html : '  '
13298 cfg.cls += ' fc-event-start';
13300 if ((i+1) == rows.length) {
13301 cfg.cls += ' fc-event-end';
13304 var ctr = _this.el.select('.fc-event-container',true).first();
13305 var cg = ctr.createChild(cfg);
13307 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13308 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13310 var r = (c.more.length) ? 1 : 0;
13311 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13312 cg.setWidth(ebox.right - sbox.x -2);
13314 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13315 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13316 cg.on('click', _this.onEventClick, _this, ev);
13327 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13328 style : 'position: absolute',
13329 unselectable : "on",
13332 cls: 'fc-event-inner',
13336 cls: 'fc-event-title',
13344 cls: 'ui-resizable-handle ui-resizable-e',
13345 html : '  '
13351 var ctr = _this.el.select('.fc-event-container',true).first();
13352 var cg = ctr.createChild(cfg);
13354 var sbox = c.select('.fc-day-content',true).first().getBox();
13355 var ebox = c.select('.fc-day-content',true).first().getBox();
13357 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13358 cg.setWidth(ebox.right - sbox.x -2);
13360 cg.on('click', _this.onMoreEventClick, _this, c.more);
13370 onEventEnter: function (e, el,event,d) {
13371 this.fireEvent('evententer', this, el, event);
13374 onEventLeave: function (e, el,event,d) {
13375 this.fireEvent('eventleave', this, el, event);
13378 onEventClick: function (e, el,event,d) {
13379 this.fireEvent('eventclick', this, el, event);
13382 onMonthChange: function () {
13386 onMoreEventClick: function(e, el, more)
13390 this.calpopover.placement = 'right';
13391 this.calpopover.setTitle('More');
13393 this.calpopover.setContent('');
13395 var ctr = this.calpopover.el.select('.popover-content', true).first();
13397 Roo.each(more, function(m){
13399 cls : 'fc-event-hori fc-event-draggable',
13402 var cg = ctr.createChild(cfg);
13404 cg.on('click', _this.onEventClick, _this, m);
13407 this.calpopover.show(el);
13412 onLoad: function ()
13414 this.calevents = [];
13417 if(this.store.getCount() > 0){
13418 this.store.data.each(function(d){
13421 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13422 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13423 time : d.data.start_time,
13424 title : d.data.title,
13425 description : d.data.description,
13426 venue : d.data.venue
13431 this.renderEvents();
13433 if(this.calevents.length && this.loadMask){
13434 this.maskEl.hide();
13438 onBeforeLoad: function()
13440 this.clearEvents();
13442 this.maskEl.show();
13456 * @class Roo.bootstrap.Popover
13457 * @extends Roo.bootstrap.Component
13458 * Bootstrap Popover class
13459 * @cfg {String} html contents of the popover (or false to use children..)
13460 * @cfg {String} title of popover (or false to hide)
13461 * @cfg {String} placement how it is placed
13462 * @cfg {String} trigger click || hover (or false to trigger manually)
13463 * @cfg {String} over what (parent or false to trigger manually.)
13466 * Create a new Popover
13467 * @param {Object} config The config object
13470 Roo.bootstrap.Popover = function(config){
13471 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13474 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13476 title: 'Fill in a title',
13479 placement : 'right',
13480 trigger : 'hover', // hover
13484 can_build_overlaid : false,
13486 getChildContainer : function()
13488 return this.el.select('.popover-content',true).first();
13491 getAutoCreate : function(){
13492 Roo.log('make popover?');
13494 cls : 'popover roo-dynamic',
13495 style: 'display:block',
13501 cls : 'popover-inner',
13505 cls: 'popover-title',
13509 cls : 'popover-content',
13520 setTitle: function(str)
13522 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13524 setContent: function(str)
13526 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13528 // as it get's added to the bottom of the page.
13529 onRender : function(ct, position)
13531 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13533 var cfg = Roo.apply({}, this.getAutoCreate());
13537 cfg.cls += ' ' + this.cls;
13540 cfg.style = this.style;
13542 Roo.log("adding to ")
13543 this.el = Roo.get(document.body).createChild(cfg, position);
13549 initEvents : function()
13551 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13552 this.el.enableDisplayMode('block');
13554 if (this.over === false) {
13557 if (this.triggers === false) {
13560 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13561 var triggers = this.trigger ? this.trigger.split(' ') : [];
13562 Roo.each(triggers, function(trigger) {
13564 if (trigger == 'click') {
13565 on_el.on('click', this.toggle, this);
13566 } else if (trigger != 'manual') {
13567 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13568 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13570 on_el.on(eventIn ,this.enter, this);
13571 on_el.on(eventOut, this.leave, this);
13582 toggle : function () {
13583 this.hoverState == 'in' ? this.leave() : this.enter();
13586 enter : function () {
13589 clearTimeout(this.timeout);
13591 this.hoverState = 'in'
13593 if (!this.delay || !this.delay.show) {
13598 this.timeout = setTimeout(function () {
13599 if (_t.hoverState == 'in') {
13602 }, this.delay.show)
13604 leave : function() {
13605 clearTimeout(this.timeout);
13607 this.hoverState = 'out'
13609 if (!this.delay || !this.delay.hide) {
13614 this.timeout = setTimeout(function () {
13615 if (_t.hoverState == 'out') {
13618 }, this.delay.hide)
13621 show : function (on_el)
13624 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13627 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13628 if (this.html !== false) {
13629 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13631 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13632 if (!this.title.length) {
13633 this.el.select('.popover-title',true).hide();
13636 var placement = typeof this.placement == 'function' ?
13637 this.placement.call(this, this.el, on_el) :
13640 var autoToken = /\s?auto?\s?/i;
13641 var autoPlace = autoToken.test(placement);
13643 placement = placement.replace(autoToken, '') || 'top';
13647 //this.el.setXY([0,0]);
13649 this.el.dom.style.display='block';
13650 this.el.addClass(placement);
13652 //this.el.appendTo(on_el);
13654 var p = this.getPosition();
13655 var box = this.el.getBox();
13660 var align = Roo.bootstrap.Popover.alignment[placement]
13661 this.el.alignTo(on_el, align[0],align[1]);
13662 //var arrow = this.el.select('.arrow',true).first();
13663 //arrow.set(align[2],
13665 this.el.addClass('in');
13666 this.hoverState = null;
13668 if (this.el.hasClass('fade')) {
13675 this.el.setXY([0,0]);
13676 this.el.removeClass('in');
13683 Roo.bootstrap.Popover.alignment = {
13684 'left' : ['r-l', [-10,0], 'right'],
13685 'right' : ['l-r', [10,0], 'left'],
13686 'bottom' : ['t-b', [0,10], 'top'],
13687 'top' : [ 'b-t', [0,-10], 'bottom']
13698 * @class Roo.bootstrap.Progress
13699 * @extends Roo.bootstrap.Component
13700 * Bootstrap Progress class
13701 * @cfg {Boolean} striped striped of the progress bar
13702 * @cfg {Boolean} active animated of the progress bar
13706 * Create a new Progress
13707 * @param {Object} config The config object
13710 Roo.bootstrap.Progress = function(config){
13711 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13714 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13719 getAutoCreate : function(){
13727 cfg.cls += ' progress-striped';
13731 cfg.cls += ' active';
13750 * @class Roo.bootstrap.ProgressBar
13751 * @extends Roo.bootstrap.Component
13752 * Bootstrap ProgressBar class
13753 * @cfg {Number} aria_valuenow aria-value now
13754 * @cfg {Number} aria_valuemin aria-value min
13755 * @cfg {Number} aria_valuemax aria-value max
13756 * @cfg {String} label label for the progress bar
13757 * @cfg {String} panel (success | info | warning | danger )
13758 * @cfg {String} role role of the progress bar
13759 * @cfg {String} sr_only text
13763 * Create a new ProgressBar
13764 * @param {Object} config The config object
13767 Roo.bootstrap.ProgressBar = function(config){
13768 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13771 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13775 aria_valuemax : 100,
13781 getAutoCreate : function()
13786 cls: 'progress-bar',
13787 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13799 cfg.role = this.role;
13802 if(this.aria_valuenow){
13803 cfg['aria-valuenow'] = this.aria_valuenow;
13806 if(this.aria_valuemin){
13807 cfg['aria-valuemin'] = this.aria_valuemin;
13810 if(this.aria_valuemax){
13811 cfg['aria-valuemax'] = this.aria_valuemax;
13814 if(this.label && !this.sr_only){
13815 cfg.html = this.label;
13819 cfg.cls += ' progress-bar-' + this.panel;
13825 update : function(aria_valuenow)
13827 this.aria_valuenow = aria_valuenow;
13829 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13844 * @class Roo.bootstrap.TabGroup
13845 * @extends Roo.bootstrap.Column
13846 * Bootstrap Column class
13847 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13848 * @cfg {Boolean} carousel true to make the group behave like a carousel
13851 * Create a new TabGroup
13852 * @param {Object} config The config object
13855 Roo.bootstrap.TabGroup = function(config){
13856 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13858 this.navId = Roo.id();
13861 Roo.bootstrap.TabGroup.register(this);
13865 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13868 transition : false,
13870 getAutoCreate : function()
13872 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13874 cfg.cls += ' tab-content';
13876 if (this.carousel) {
13877 cfg.cls += ' carousel slide';
13879 cls : 'carousel-inner'
13886 getChildContainer : function()
13888 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13892 * register a Navigation item
13893 * @param {Roo.bootstrap.NavItem} the navitem to add
13895 register : function(item)
13897 this.tabs.push( item);
13898 item.navId = this.navId; // not really needed..
13902 getActivePanel : function()
13905 Roo.each(this.tabs, function(t) {
13915 getPanelByName : function(n)
13918 Roo.each(this.tabs, function(t) {
13919 if (t.tabId == n) {
13927 indexOfPanel : function(p)
13930 Roo.each(this.tabs, function(t,i) {
13931 if (t.tabId == p.tabId) {
13940 * show a specific panel
13941 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13942 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13944 showPanel : function (pan)
13947 if (typeof(pan) == 'number') {
13948 pan = this.tabs[pan];
13950 if (typeof(pan) == 'string') {
13951 pan = this.getPanelByName(pan);
13953 if (pan.tabId == this.getActivePanel().tabId) {
13956 var cur = this.getActivePanel();
13958 if (false === cur.fireEvent('beforedeactivate')) {
13962 if (this.carousel) {
13963 this.transition = true;
13964 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13965 var lr = dir == 'next' ? 'left' : 'right';
13966 pan.el.addClass(dir); // or prev
13967 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13968 cur.el.addClass(lr); // or right
13969 pan.el.addClass(lr);
13972 cur.el.on('transitionend', function() {
13973 Roo.log("trans end?");
13975 pan.el.removeClass([lr,dir]);
13976 pan.setActive(true);
13978 cur.el.removeClass([lr]);
13979 cur.setActive(false);
13981 _this.transition = false;
13983 }, this, { single: true } );
13987 cur.setActive(false);
13988 pan.setActive(true);
13992 showPanelNext : function()
13994 var i = this.indexOfPanel(this.getActivePanel());
13995 if (i > this.tabs.length) {
13998 this.showPanel(this.tabs[i+1]);
14000 showPanelPrev : function()
14002 var i = this.indexOfPanel(this.getActivePanel());
14006 this.showPanel(this.tabs[i-1]);
14017 Roo.apply(Roo.bootstrap.TabGroup, {
14021 * register a Navigation Group
14022 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14024 register : function(navgrp)
14026 this.groups[navgrp.navId] = navgrp;
14030 * fetch a Navigation Group based on the navigation ID
14031 * if one does not exist , it will get created.
14032 * @param {string} the navgroup to add
14033 * @returns {Roo.bootstrap.NavGroup} the navgroup
14035 get: function(navId) {
14036 if (typeof(this.groups[navId]) == 'undefined') {
14037 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14039 return this.groups[navId] ;
14054 * @class Roo.bootstrap.TabPanel
14055 * @extends Roo.bootstrap.Component
14056 * Bootstrap TabPanel class
14057 * @cfg {Boolean} active panel active
14058 * @cfg {String} html panel content
14059 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14060 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14064 * Create a new TabPanel
14065 * @param {Object} config The config object
14068 Roo.bootstrap.TabPanel = function(config){
14069 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14073 * Fires when the active status changes
14074 * @param {Roo.bootstrap.TabPanel} this
14075 * @param {Boolean} state the new state
14080 * @event beforedeactivate
14081 * Fires before a tab is de-activated - can be used to do validation on a form.
14082 * @param {Roo.bootstrap.TabPanel} this
14083 * @return {Boolean} false if there is an error
14086 'beforedeactivate': true
14089 this.tabId = this.tabId || Roo.id();
14093 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14100 getAutoCreate : function(){
14103 // item is needed for carousel - not sure if it has any effect otherwise
14104 cls: 'tab-pane item',
14105 html: this.html || ''
14109 cfg.cls += ' active';
14113 cfg.tabId = this.tabId;
14120 initEvents: function()
14122 Roo.log('-------- init events on tab panel ---------');
14124 var p = this.parent();
14125 this.navId = this.navId || p.navId;
14127 if (typeof(this.navId) != 'undefined') {
14128 // not really needed.. but just in case.. parent should be a NavGroup.
14129 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14130 Roo.log(['register', tg, this]);
14136 onRender : function(ct, position)
14138 // Roo.log("Call onRender: " + this.xtype);
14140 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14148 setActive: function(state)
14150 Roo.log("panel - set active " + this.tabId + "=" + state);
14152 this.active = state;
14154 this.el.removeClass('active');
14156 } else if (!this.el.hasClass('active')) {
14157 this.el.addClass('active');
14159 this.fireEvent('changed', this, state);
14176 * @class Roo.bootstrap.DateField
14177 * @extends Roo.bootstrap.Input
14178 * Bootstrap DateField class
14179 * @cfg {Number} weekStart default 0
14180 * @cfg {Number} weekStart default 0
14181 * @cfg {Number} viewMode default empty, (months|years)
14182 * @cfg {Number} minViewMode default empty, (months|years)
14183 * @cfg {Number} startDate default -Infinity
14184 * @cfg {Number} endDate default Infinity
14185 * @cfg {Boolean} todayHighlight default false
14186 * @cfg {Boolean} todayBtn default false
14187 * @cfg {Boolean} calendarWeeks default false
14188 * @cfg {Object} daysOfWeekDisabled default empty
14190 * @cfg {Boolean} keyboardNavigation default true
14191 * @cfg {String} language default en
14194 * Create a new DateField
14195 * @param {Object} config The config object
14198 Roo.bootstrap.DateField = function(config){
14199 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14203 * Fires when this field show.
14204 * @param {Roo.bootstrap.DateField} this
14205 * @param {Mixed} date The date value
14210 * Fires when this field hide.
14211 * @param {Roo.bootstrap.DateField} this
14212 * @param {Mixed} date The date value
14217 * Fires when select a date.
14218 * @param {Roo.bootstrap.DateField} this
14219 * @param {Mixed} date The date value
14225 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14228 * @cfg {String} format
14229 * The default date format string which can be overriden for localization support. The format must be
14230 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14234 * @cfg {String} altFormats
14235 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14236 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14238 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14246 todayHighlight : false,
14252 keyboardNavigation: true,
14254 calendarWeeks: false,
14256 startDate: -Infinity,
14260 daysOfWeekDisabled: [],
14264 UTCDate: function()
14266 return new Date(Date.UTC.apply(Date, arguments));
14269 UTCToday: function()
14271 var today = new Date();
14272 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14275 getDate: function() {
14276 var d = this.getUTCDate();
14277 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14280 getUTCDate: function() {
14284 setDate: function(d) {
14285 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14288 setUTCDate: function(d) {
14290 this.setValue(this.formatDate(this.date));
14293 onRender: function(ct, position)
14296 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14298 this.language = this.language || 'en';
14299 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14300 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14302 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14303 this.format = this.format || 'm/d/y';
14304 this.isInline = false;
14305 this.isInput = true;
14306 this.component = this.el.select('.add-on', true).first() || false;
14307 this.component = (this.component && this.component.length === 0) ? false : this.component;
14308 this.hasInput = this.component && this.inputEL().length;
14310 if (typeof(this.minViewMode === 'string')) {
14311 switch (this.minViewMode) {
14313 this.minViewMode = 1;
14316 this.minViewMode = 2;
14319 this.minViewMode = 0;
14324 if (typeof(this.viewMode === 'string')) {
14325 switch (this.viewMode) {
14338 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14340 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14342 this.picker().on('mousedown', this.onMousedown, this);
14343 this.picker().on('click', this.onClick, this);
14345 this.picker().addClass('datepicker-dropdown');
14347 this.startViewMode = this.viewMode;
14350 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14351 if(!this.calendarWeeks){
14356 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14357 v.attr('colspan', function(i, val){
14358 return parseInt(val) + 1;
14363 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14365 this.setStartDate(this.startDate);
14366 this.setEndDate(this.endDate);
14368 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14375 if(this.isInline) {
14380 picker : function()
14382 return this.el.select('.datepicker', true).first();
14385 fillDow: function()
14387 var dowCnt = this.weekStart;
14396 if(this.calendarWeeks){
14404 while (dowCnt < this.weekStart + 7) {
14408 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14412 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14415 fillMonths: function()
14418 var months = this.picker().select('>.datepicker-months td', true).first();
14420 months.dom.innerHTML = '';
14426 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14429 months.createChild(month);
14437 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14439 if (this.date < this.startDate) {
14440 this.viewDate = new Date(this.startDate);
14441 } else if (this.date > this.endDate) {
14442 this.viewDate = new Date(this.endDate);
14444 this.viewDate = new Date(this.date);
14452 var d = new Date(this.viewDate),
14453 year = d.getUTCFullYear(),
14454 month = d.getUTCMonth(),
14455 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14456 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14457 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14458 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14459 currentDate = this.date && this.date.valueOf(),
14460 today = this.UTCToday();
14462 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14464 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14466 // this.picker.select('>tfoot th.today').
14467 // .text(dates[this.language].today)
14468 // .toggle(this.todayBtn !== false);
14470 this.updateNavArrows();
14473 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14475 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14477 prevMonth.setUTCDate(day);
14479 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14481 var nextMonth = new Date(prevMonth);
14483 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14485 nextMonth = nextMonth.valueOf();
14487 var fillMonths = false;
14489 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14491 while(prevMonth.valueOf() < nextMonth) {
14494 if (prevMonth.getUTCDay() === this.weekStart) {
14496 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14504 if(this.calendarWeeks){
14505 // ISO 8601: First week contains first thursday.
14506 // ISO also states week starts on Monday, but we can be more abstract here.
14508 // Start of current week: based on weekstart/current date
14509 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14510 // Thursday of this week
14511 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14512 // First Thursday of year, year from thursday
14513 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14514 // Calendar week: ms between thursdays, div ms per day, div 7 days
14515 calWeek = (th - yth) / 864e5 / 7 + 1;
14517 fillMonths.cn.push({
14525 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14527 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14530 if (this.todayHighlight &&
14531 prevMonth.getUTCFullYear() == today.getFullYear() &&
14532 prevMonth.getUTCMonth() == today.getMonth() &&
14533 prevMonth.getUTCDate() == today.getDate()) {
14534 clsName += ' today';
14537 if (currentDate && prevMonth.valueOf() === currentDate) {
14538 clsName += ' active';
14541 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14542 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14543 clsName += ' disabled';
14546 fillMonths.cn.push({
14548 cls: 'day ' + clsName,
14549 html: prevMonth.getDate()
14552 prevMonth.setDate(prevMonth.getDate()+1);
14555 var currentYear = this.date && this.date.getUTCFullYear();
14556 var currentMonth = this.date && this.date.getUTCMonth();
14558 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14560 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14561 v.removeClass('active');
14563 if(currentYear === year && k === currentMonth){
14564 v.addClass('active');
14567 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14568 v.addClass('disabled');
14574 year = parseInt(year/10, 10) * 10;
14576 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14578 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14581 for (var i = -1; i < 11; i++) {
14582 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14584 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14592 showMode: function(dir)
14595 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14597 Roo.each(this.picker().select('>div',true).elements, function(v){
14598 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14601 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14606 if(this.isInline) return;
14608 this.picker().removeClass(['bottom', 'top']);
14610 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14612 * place to the top of element!
14616 this.picker().addClass('top');
14617 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14622 this.picker().addClass('bottom');
14624 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14627 parseDate : function(value)
14629 if(!value || value instanceof Date){
14632 var v = Date.parseDate(value, this.format);
14633 if (!v && this.useIso) {
14634 v = Date.parseDate(value, 'Y-m-d');
14636 if(!v && this.altFormats){
14637 if(!this.altFormatsArray){
14638 this.altFormatsArray = this.altFormats.split("|");
14640 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14641 v = Date.parseDate(value, this.altFormatsArray[i]);
14647 formatDate : function(date, fmt)
14649 return (!date || !(date instanceof Date)) ?
14650 date : date.dateFormat(fmt || this.format);
14653 onFocus : function()
14655 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14659 onBlur : function()
14661 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14663 var d = this.inputEl().getValue();
14674 this.picker().show();
14678 this.fireEvent('show', this, this.date);
14683 if(this.isInline) return;
14684 this.picker().hide();
14685 this.viewMode = this.startViewMode;
14688 this.fireEvent('hide', this, this.date);
14692 onMousedown: function(e)
14694 e.stopPropagation();
14695 e.preventDefault();
14700 Roo.bootstrap.DateField.superclass.keyup.call(this);
14704 setValue: function(v)
14706 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14708 var d = new Date(v);
14710 if(isNaN(d.getTime())){
14714 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14718 this.fireEvent('select', this, this.date);
14722 getValue: function()
14724 return this.formatDate(this.date);
14727 fireKey: function(e)
14729 if (!this.picker().isVisible()){
14730 if (e.keyCode == 27) // allow escape to hide and re-show picker
14735 var dateChanged = false,
14737 newDate, newViewDate;
14742 e.preventDefault();
14746 if (!this.keyboardNavigation) break;
14747 dir = e.keyCode == 37 ? -1 : 1;
14750 newDate = this.moveYear(this.date, dir);
14751 newViewDate = this.moveYear(this.viewDate, dir);
14752 } else if (e.shiftKey){
14753 newDate = this.moveMonth(this.date, dir);
14754 newViewDate = this.moveMonth(this.viewDate, dir);
14756 newDate = new Date(this.date);
14757 newDate.setUTCDate(this.date.getUTCDate() + dir);
14758 newViewDate = new Date(this.viewDate);
14759 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14761 if (this.dateWithinRange(newDate)){
14762 this.date = newDate;
14763 this.viewDate = newViewDate;
14764 this.setValue(this.formatDate(this.date));
14766 e.preventDefault();
14767 dateChanged = true;
14772 if (!this.keyboardNavigation) break;
14773 dir = e.keyCode == 38 ? -1 : 1;
14775 newDate = this.moveYear(this.date, dir);
14776 newViewDate = this.moveYear(this.viewDate, dir);
14777 } else if (e.shiftKey){
14778 newDate = this.moveMonth(this.date, dir);
14779 newViewDate = this.moveMonth(this.viewDate, dir);
14781 newDate = new Date(this.date);
14782 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14783 newViewDate = new Date(this.viewDate);
14784 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14786 if (this.dateWithinRange(newDate)){
14787 this.date = newDate;
14788 this.viewDate = newViewDate;
14789 this.setValue(this.formatDate(this.date));
14791 e.preventDefault();
14792 dateChanged = true;
14796 this.setValue(this.formatDate(this.date));
14798 e.preventDefault();
14801 this.setValue(this.formatDate(this.date));
14815 onClick: function(e)
14817 e.stopPropagation();
14818 e.preventDefault();
14820 var target = e.getTarget();
14822 if(target.nodeName.toLowerCase() === 'i'){
14823 target = Roo.get(target).dom.parentNode;
14826 var nodeName = target.nodeName;
14827 var className = target.className;
14828 var html = target.innerHTML;
14830 switch(nodeName.toLowerCase()) {
14832 switch(className) {
14838 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14839 switch(this.viewMode){
14841 this.viewDate = this.moveMonth(this.viewDate, dir);
14845 this.viewDate = this.moveYear(this.viewDate, dir);
14851 var date = new Date();
14852 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14854 this.setValue(this.formatDate(this.date));
14861 if (className.indexOf('disabled') === -1) {
14862 this.viewDate.setUTCDate(1);
14863 if (className.indexOf('month') !== -1) {
14864 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14866 var year = parseInt(html, 10) || 0;
14867 this.viewDate.setUTCFullYear(year);
14876 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14877 var day = parseInt(html, 10) || 1;
14878 var year = this.viewDate.getUTCFullYear(),
14879 month = this.viewDate.getUTCMonth();
14881 if (className.indexOf('old') !== -1) {
14888 } else if (className.indexOf('new') !== -1) {
14896 this.date = this.UTCDate(year, month, day,0,0,0,0);
14897 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14899 this.setValue(this.formatDate(this.date));
14906 setStartDate: function(startDate)
14908 this.startDate = startDate || -Infinity;
14909 if (this.startDate !== -Infinity) {
14910 this.startDate = this.parseDate(this.startDate);
14913 this.updateNavArrows();
14916 setEndDate: function(endDate)
14918 this.endDate = endDate || Infinity;
14919 if (this.endDate !== Infinity) {
14920 this.endDate = this.parseDate(this.endDate);
14923 this.updateNavArrows();
14926 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14928 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14929 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14930 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14932 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14933 return parseInt(d, 10);
14936 this.updateNavArrows();
14939 updateNavArrows: function()
14941 var d = new Date(this.viewDate),
14942 year = d.getUTCFullYear(),
14943 month = d.getUTCMonth();
14945 Roo.each(this.picker().select('.prev', true).elements, function(v){
14947 switch (this.viewMode) {
14950 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14956 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14963 Roo.each(this.picker().select('.next', true).elements, function(v){
14965 switch (this.viewMode) {
14968 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14974 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14982 moveMonth: function(date, dir)
14984 if (!dir) return date;
14985 var new_date = new Date(date.valueOf()),
14986 day = new_date.getUTCDate(),
14987 month = new_date.getUTCMonth(),
14988 mag = Math.abs(dir),
14990 dir = dir > 0 ? 1 : -1;
14993 // If going back one month, make sure month is not current month
14994 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14996 return new_date.getUTCMonth() == month;
14998 // If going forward one month, make sure month is as expected
14999 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15001 return new_date.getUTCMonth() != new_month;
15003 new_month = month + dir;
15004 new_date.setUTCMonth(new_month);
15005 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15006 if (new_month < 0 || new_month > 11)
15007 new_month = (new_month + 12) % 12;
15009 // For magnitudes >1, move one month at a time...
15010 for (var i=0; i<mag; i++)
15011 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15012 new_date = this.moveMonth(new_date, dir);
15013 // ...then reset the day, keeping it in the new month
15014 new_month = new_date.getUTCMonth();
15015 new_date.setUTCDate(day);
15017 return new_month != new_date.getUTCMonth();
15020 // Common date-resetting loop -- if date is beyond end of month, make it
15023 new_date.setUTCDate(--day);
15024 new_date.setUTCMonth(new_month);
15029 moveYear: function(date, dir)
15031 return this.moveMonth(date, dir*12);
15034 dateWithinRange: function(date)
15036 return date >= this.startDate && date <= this.endDate;
15042 this.picker().remove();
15047 Roo.apply(Roo.bootstrap.DateField, {
15058 html: '<i class="fa fa-arrow-left"/>'
15068 html: '<i class="fa fa-arrow-right"/>'
15110 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15111 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15112 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15113 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15114 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15127 navFnc: 'FullYear',
15132 navFnc: 'FullYear',
15137 Roo.apply(Roo.bootstrap.DateField, {
15141 cls: 'datepicker dropdown-menu',
15145 cls: 'datepicker-days',
15149 cls: 'table-condensed',
15151 Roo.bootstrap.DateField.head,
15155 Roo.bootstrap.DateField.footer
15162 cls: 'datepicker-months',
15166 cls: 'table-condensed',
15168 Roo.bootstrap.DateField.head,
15169 Roo.bootstrap.DateField.content,
15170 Roo.bootstrap.DateField.footer
15177 cls: 'datepicker-years',
15181 cls: 'table-condensed',
15183 Roo.bootstrap.DateField.head,
15184 Roo.bootstrap.DateField.content,
15185 Roo.bootstrap.DateField.footer
15204 * @class Roo.bootstrap.TimeField
15205 * @extends Roo.bootstrap.Input
15206 * Bootstrap DateField class
15210 * Create a new TimeField
15211 * @param {Object} config The config object
15214 Roo.bootstrap.TimeField = function(config){
15215 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15219 * Fires when this field show.
15220 * @param {Roo.bootstrap.DateField} this
15221 * @param {Mixed} date The date value
15226 * Fires when this field hide.
15227 * @param {Roo.bootstrap.DateField} this
15228 * @param {Mixed} date The date value
15233 * Fires when select a date.
15234 * @param {Roo.bootstrap.DateField} this
15235 * @param {Mixed} date The date value
15241 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15244 * @cfg {String} format
15245 * The default time format string which can be overriden for localization support. The format must be
15246 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15250 onRender: function(ct, position)
15253 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15255 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15257 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15259 this.pop = this.picker().select('>.datepicker-time',true).first();
15260 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15262 this.picker().on('mousedown', this.onMousedown, this);
15263 this.picker().on('click', this.onClick, this);
15265 this.picker().addClass('datepicker-dropdown');
15270 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15271 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15272 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15273 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15274 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15275 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15279 fireKey: function(e){
15280 if (!this.picker().isVisible()){
15281 if (e.keyCode == 27) // allow escape to hide and re-show picker
15286 e.preventDefault();
15294 this.onTogglePeriod();
15297 this.onIncrementMinutes();
15300 this.onDecrementMinutes();
15309 onClick: function(e) {
15310 e.stopPropagation();
15311 e.preventDefault();
15314 picker : function()
15316 return this.el.select('.datepicker', true).first();
15319 fillTime: function()
15321 var time = this.pop.select('tbody', true).first();
15323 time.dom.innerHTML = '';
15338 cls: 'hours-up glyphicon glyphicon-chevron-up'
15358 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15379 cls: 'timepicker-hour',
15394 cls: 'timepicker-minute',
15409 cls: 'btn btn-primary period',
15431 cls: 'hours-down glyphicon glyphicon-chevron-down'
15451 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15469 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15476 var hours = this.time.getHours();
15477 var minutes = this.time.getMinutes();
15490 hours = hours - 12;
15494 hours = '0' + hours;
15498 minutes = '0' + minutes;
15501 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15502 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15503 this.pop.select('button', true).first().dom.innerHTML = period;
15509 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15511 var cls = ['bottom'];
15513 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15520 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15525 this.picker().addClass(cls.join('-'));
15529 Roo.each(cls, function(c){
15531 _this.picker().setTop(_this.inputEl().getHeight());
15535 _this.picker().setTop(0 - _this.picker().getHeight());
15540 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15544 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15551 onFocus : function()
15553 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15557 onBlur : function()
15559 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15565 this.picker().show();
15570 this.fireEvent('show', this, this.date);
15575 this.picker().hide();
15578 this.fireEvent('hide', this, this.date);
15581 setTime : function()
15584 this.setValue(this.time.format(this.format));
15586 this.fireEvent('select', this, this.date);
15591 onMousedown: function(e){
15592 e.stopPropagation();
15593 e.preventDefault();
15596 onIncrementHours: function()
15598 Roo.log('onIncrementHours');
15599 this.time = this.time.add(Date.HOUR, 1);
15604 onDecrementHours: function()
15606 Roo.log('onDecrementHours');
15607 this.time = this.time.add(Date.HOUR, -1);
15611 onIncrementMinutes: function()
15613 Roo.log('onIncrementMinutes');
15614 this.time = this.time.add(Date.MINUTE, 1);
15618 onDecrementMinutes: function()
15620 Roo.log('onDecrementMinutes');
15621 this.time = this.time.add(Date.MINUTE, -1);
15625 onTogglePeriod: function()
15627 Roo.log('onTogglePeriod');
15628 this.time = this.time.add(Date.HOUR, 12);
15635 Roo.apply(Roo.bootstrap.TimeField, {
15665 cls: 'btn btn-info ok',
15677 Roo.apply(Roo.bootstrap.TimeField, {
15681 cls: 'datepicker dropdown-menu',
15685 cls: 'datepicker-time',
15689 cls: 'table-condensed',
15691 Roo.bootstrap.TimeField.content,
15692 Roo.bootstrap.TimeField.footer
15711 * @class Roo.bootstrap.CheckBox
15712 * @extends Roo.bootstrap.Input
15713 * Bootstrap CheckBox class
15715 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15716 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15717 * @cfg {String} boxLabel The text that appears beside the checkbox
15718 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15719 * @cfg {Boolean} checked initnal the element
15723 * Create a new CheckBox
15724 * @param {Object} config The config object
15727 Roo.bootstrap.CheckBox = function(config){
15728 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15733 * Fires when the element is checked or unchecked.
15734 * @param {Roo.bootstrap.CheckBox} this This input
15735 * @param {Boolean} checked The new checked value
15741 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15743 inputType: 'checkbox',
15750 getAutoCreate : function()
15752 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15758 cfg.cls = 'form-group checkbox' //input-group
15766 type : this.inputType,
15767 value : (!this.checked) ? this.valueOff : this.inputValue,
15768 cls : 'roo-checkbox', //'form-box',
15769 placeholder : this.placeholder || ''
15773 if (this.weight) { // Validity check?
15774 cfg.cls += " checkbox-" + this.weight;
15777 if (this.disabled) {
15778 input.disabled=true;
15782 input.checked = this.checked;
15786 input.name = this.name;
15790 input.cls += ' input-' + this.size;
15794 ['xs','sm','md','lg'].map(function(size){
15795 if (settings[size]) {
15796 cfg.cls += ' col-' + size + '-' + settings[size];
15802 var inputblock = input;
15807 if (this.before || this.after) {
15810 cls : 'input-group',
15814 inputblock.cn.push({
15816 cls : 'input-group-addon',
15820 inputblock.cn.push(input);
15822 inputblock.cn.push({
15824 cls : 'input-group-addon',
15831 if (align ==='left' && this.fieldLabel.length) {
15832 Roo.log("left and has label");
15838 cls : 'control-label col-md-' + this.labelWidth,
15839 html : this.fieldLabel
15843 cls : "col-md-" + (12 - this.labelWidth),
15850 } else if ( this.fieldLabel.length) {
15855 tag: this.boxLabel ? 'span' : 'label',
15857 cls: 'control-label box-input-label',
15858 //cls : 'input-group-addon',
15859 html : this.fieldLabel
15869 Roo.log(" no label && no align");
15870 cfg.cn = [ inputblock ] ;
15879 html: this.boxLabel
15891 * return the real input element.
15893 inputEl: function ()
15895 return this.el.select('input.roo-checkbox',true).first();
15900 return this.el.select('label.control-label',true).first();
15903 initEvents : function()
15905 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15907 this.inputEl().on('click', this.onClick, this);
15911 onClick : function()
15913 this.setChecked(!this.checked);
15916 setChecked : function(state,suppressEvent)
15918 this.checked = state;
15920 this.inputEl().dom.checked = state;
15922 if(suppressEvent !== true){
15923 this.fireEvent('check', this, state);
15926 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15930 setValue : function(v,suppressEvent)
15932 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15946 * @class Roo.bootstrap.Radio
15947 * @extends Roo.bootstrap.CheckBox
15948 * Bootstrap Radio class
15951 * Create a new Radio
15952 * @param {Object} config The config object
15955 Roo.bootstrap.Radio = function(config){
15956 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15960 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15962 inputType: 'radio',
15966 getAutoCreate : function()
15968 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15974 cfg.cls = 'form-group radio' //input-group
15979 type : this.inputType,
15980 value : (!this.checked) ? this.valueOff : this.inputValue,
15982 placeholder : this.placeholder || ''
15985 if (this.weight) { // Validity check?
15986 cfg.cls += " radio-" + this.weight;
15988 if (this.disabled) {
15989 input.disabled=true;
15993 input.checked = this.checked;
15997 input.name = this.name;
16001 input.cls += ' input-' + this.size;
16005 ['xs','sm','md','lg'].map(function(size){
16006 if (settings[size]) {
16007 cfg.cls += ' col-' + size + '-' + settings[size];
16011 var inputblock = input;
16013 if (this.before || this.after) {
16016 cls : 'input-group',
16020 inputblock.cn.push({
16022 cls : 'input-group-addon',
16026 inputblock.cn.push(input);
16028 inputblock.cn.push({
16030 cls : 'input-group-addon',
16037 if (align ==='left' && this.fieldLabel.length) {
16038 Roo.log("left and has label");
16044 cls : 'control-label col-md-' + this.labelWidth,
16045 html : this.fieldLabel
16049 cls : "col-md-" + (12 - this.labelWidth),
16056 } else if ( this.fieldLabel.length) {
16063 cls: 'control-label box-input-label',
16064 //cls : 'input-group-addon',
16065 html : this.fieldLabel
16075 Roo.log(" no label && no align");
16090 html: this.boxLabel
16097 inputEl: function ()
16099 return this.el.select('input.roo-radio',true).first();
16101 onClick : function()
16103 this.setChecked(true);
16106 setChecked : function(state,suppressEvent)
16109 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16110 v.dom.checked = false;
16114 this.checked = state;
16115 this.inputEl().dom.checked = state;
16117 if(suppressEvent !== true){
16118 this.fireEvent('check', this, state);
16121 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16125 getGroupValue : function()
16128 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16129 if(v.dom.checked == true){
16130 value = v.dom.value;
16138 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16139 * @return {Mixed} value The field value
16141 getValue : function(){
16142 return this.getGroupValue();
16148 //<script type="text/javascript">
16151 * Based Ext JS Library 1.1.1
16152 * Copyright(c) 2006-2007, Ext JS, LLC.
16158 * @class Roo.HtmlEditorCore
16159 * @extends Roo.Component
16160 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16162 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16165 Roo.HtmlEditorCore = function(config){
16168 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16171 * @event initialize
16172 * Fires when the editor is fully initialized (including the iframe)
16173 * @param {Roo.HtmlEditorCore} this
16178 * Fires when the editor is first receives the focus. Any insertion must wait
16179 * until after this event.
16180 * @param {Roo.HtmlEditorCore} this
16184 * @event beforesync
16185 * Fires before the textarea is updated with content from the editor iframe. Return false
16186 * to cancel the sync.
16187 * @param {Roo.HtmlEditorCore} this
16188 * @param {String} html
16192 * @event beforepush
16193 * Fires before the iframe editor is updated with content from the textarea. Return false
16194 * to cancel the push.
16195 * @param {Roo.HtmlEditorCore} this
16196 * @param {String} html
16201 * Fires when the textarea is updated with content from the editor iframe.
16202 * @param {Roo.HtmlEditorCore} this
16203 * @param {String} html
16208 * Fires when the iframe editor is updated with content from the textarea.
16209 * @param {Roo.HtmlEditorCore} this
16210 * @param {String} html
16215 * @event editorevent
16216 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16217 * @param {Roo.HtmlEditorCore} this
16225 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16229 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16235 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16240 * @cfg {Number} height (in pixels)
16244 * @cfg {Number} width (in pixels)
16249 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16252 stylesheets: false,
16257 // private properties
16258 validationEvent : false,
16260 initialized : false,
16262 sourceEditMode : false,
16263 onFocus : Roo.emptyFn,
16265 hideMode:'offsets',
16273 * Protected method that will not generally be called directly. It
16274 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16275 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16277 getDocMarkup : function(){
16280 Roo.log(this.stylesheets);
16282 // inherit styels from page...??
16283 if (this.stylesheets === false) {
16285 Roo.get(document.head).select('style').each(function(node) {
16286 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16289 Roo.get(document.head).select('link').each(function(node) {
16290 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16293 } else if (!this.stylesheets.length) {
16295 st = '<style type="text/css">' +
16296 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16299 Roo.each(this.stylesheets, function(s) {
16300 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16305 st += '<style type="text/css">' +
16306 'IMG { cursor: pointer } ' +
16310 return '<html><head>' + st +
16311 //<style type="text/css">' +
16312 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16314 ' </head><body class="roo-htmleditor-body"></body></html>';
16318 onRender : function(ct, position)
16321 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16322 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16325 this.el.dom.style.border = '0 none';
16326 this.el.dom.setAttribute('tabIndex', -1);
16327 this.el.addClass('x-hidden hide');
16331 if(Roo.isIE){ // fix IE 1px bogus margin
16332 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16336 this.frameId = Roo.id();
16340 var iframe = this.owner.wrap.createChild({
16342 cls: 'form-control', // bootstrap..
16344 name: this.frameId,
16345 frameBorder : 'no',
16346 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16351 this.iframe = iframe.dom;
16353 this.assignDocWin();
16355 this.doc.designMode = 'on';
16358 this.doc.write(this.getDocMarkup());
16362 var task = { // must defer to wait for browser to be ready
16364 //console.log("run task?" + this.doc.readyState);
16365 this.assignDocWin();
16366 if(this.doc.body || this.doc.readyState == 'complete'){
16368 this.doc.designMode="on";
16372 Roo.TaskMgr.stop(task);
16373 this.initEditor.defer(10, this);
16380 Roo.TaskMgr.start(task);
16387 onResize : function(w, h)
16389 Roo.log('resize: ' +w + ',' + h );
16390 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16394 if(typeof w == 'number'){
16396 this.iframe.style.width = w + 'px';
16398 if(typeof h == 'number'){
16400 this.iframe.style.height = h + 'px';
16402 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16409 * Toggles the editor between standard and source edit mode.
16410 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16412 toggleSourceEdit : function(sourceEditMode){
16414 this.sourceEditMode = sourceEditMode === true;
16416 if(this.sourceEditMode){
16418 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16421 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16422 //this.iframe.className = '';
16425 //this.setSize(this.owner.wrap.getSize());
16426 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16433 * Protected method that will not generally be called directly. If you need/want
16434 * custom HTML cleanup, this is the method you should override.
16435 * @param {String} html The HTML to be cleaned
16436 * return {String} The cleaned HTML
16438 cleanHtml : function(html){
16439 html = String(html);
16440 if(html.length > 5){
16441 if(Roo.isSafari){ // strip safari nonsense
16442 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16445 if(html == ' '){
16452 * HTML Editor -> Textarea
16453 * Protected method that will not generally be called directly. Syncs the contents
16454 * of the editor iframe with the textarea.
16456 syncValue : function(){
16457 if(this.initialized){
16458 var bd = (this.doc.body || this.doc.documentElement);
16459 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16460 var html = bd.innerHTML;
16462 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16463 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16465 html = '<div style="'+m[0]+'">' + html + '</div>';
16468 html = this.cleanHtml(html);
16469 // fix up the special chars.. normaly like back quotes in word...
16470 // however we do not want to do this with chinese..
16471 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16472 var cc = b.charCodeAt();
16474 (cc >= 0x4E00 && cc < 0xA000 ) ||
16475 (cc >= 0x3400 && cc < 0x4E00 ) ||
16476 (cc >= 0xf900 && cc < 0xfb00 )
16482 if(this.owner.fireEvent('beforesync', this, html) !== false){
16483 this.el.dom.value = html;
16484 this.owner.fireEvent('sync', this, html);
16490 * Protected method that will not generally be called directly. Pushes the value of the textarea
16491 * into the iframe editor.
16493 pushValue : function(){
16494 if(this.initialized){
16495 var v = this.el.dom.value.trim();
16497 // if(v.length < 1){
16501 if(this.owner.fireEvent('beforepush', this, v) !== false){
16502 var d = (this.doc.body || this.doc.documentElement);
16504 this.cleanUpPaste();
16505 this.el.dom.value = d.innerHTML;
16506 this.owner.fireEvent('push', this, v);
16512 deferFocus : function(){
16513 this.focus.defer(10, this);
16517 focus : function(){
16518 if(this.win && !this.sourceEditMode){
16525 assignDocWin: function()
16527 var iframe = this.iframe;
16530 this.doc = iframe.contentWindow.document;
16531 this.win = iframe.contentWindow;
16533 if (!Roo.get(this.frameId)) {
16536 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16537 this.win = Roo.get(this.frameId).dom.contentWindow;
16542 initEditor : function(){
16543 //console.log("INIT EDITOR");
16544 this.assignDocWin();
16548 this.doc.designMode="on";
16550 this.doc.write(this.getDocMarkup());
16553 var dbody = (this.doc.body || this.doc.documentElement);
16554 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16555 // this copies styles from the containing element into thsi one..
16556 // not sure why we need all of this..
16557 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16559 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16560 //ss['background-attachment'] = 'fixed'; // w3c
16561 dbody.bgProperties = 'fixed'; // ie
16562 //Roo.DomHelper.applyStyles(dbody, ss);
16563 Roo.EventManager.on(this.doc, {
16564 //'mousedown': this.onEditorEvent,
16565 'mouseup': this.onEditorEvent,
16566 'dblclick': this.onEditorEvent,
16567 'click': this.onEditorEvent,
16568 'keyup': this.onEditorEvent,
16573 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16575 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16576 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16578 this.initialized = true;
16580 this.owner.fireEvent('initialize', this);
16585 onDestroy : function(){
16591 //for (var i =0; i < this.toolbars.length;i++) {
16592 // // fixme - ask toolbars for heights?
16593 // this.toolbars[i].onDestroy();
16596 //this.wrap.dom.innerHTML = '';
16597 //this.wrap.remove();
16602 onFirstFocus : function(){
16604 this.assignDocWin();
16607 this.activated = true;
16610 if(Roo.isGecko){ // prevent silly gecko errors
16612 var s = this.win.getSelection();
16613 if(!s.focusNode || s.focusNode.nodeType != 3){
16614 var r = s.getRangeAt(0);
16615 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16620 this.execCmd('useCSS', true);
16621 this.execCmd('styleWithCSS', false);
16624 this.owner.fireEvent('activate', this);
16628 adjustFont: function(btn){
16629 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16630 //if(Roo.isSafari){ // safari
16633 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16634 if(Roo.isSafari){ // safari
16635 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16636 v = (v < 10) ? 10 : v;
16637 v = (v > 48) ? 48 : v;
16638 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16643 v = Math.max(1, v+adjust);
16645 this.execCmd('FontSize', v );
16648 onEditorEvent : function(e){
16649 this.owner.fireEvent('editorevent', this, e);
16650 // this.updateToolbar();
16651 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16654 insertTag : function(tg)
16656 // could be a bit smarter... -> wrap the current selected tRoo..
16657 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16659 range = this.createRange(this.getSelection());
16660 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16661 wrappingNode.appendChild(range.extractContents());
16662 range.insertNode(wrappingNode);
16669 this.execCmd("formatblock", tg);
16673 insertText : function(txt)
16677 var range = this.createRange();
16678 range.deleteContents();
16679 //alert(Sender.getAttribute('label'));
16681 range.insertNode(this.doc.createTextNode(txt));
16687 * Executes a Midas editor command on the editor document and performs necessary focus and
16688 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16689 * @param {String} cmd The Midas command
16690 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16692 relayCmd : function(cmd, value){
16694 this.execCmd(cmd, value);
16695 this.owner.fireEvent('editorevent', this);
16696 //this.updateToolbar();
16697 this.owner.deferFocus();
16701 * Executes a Midas editor command directly on the editor document.
16702 * For visual commands, you should use {@link #relayCmd} instead.
16703 * <b>This should only be called after the editor is initialized.</b>
16704 * @param {String} cmd The Midas command
16705 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16707 execCmd : function(cmd, value){
16708 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16715 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16717 * @param {String} text | dom node..
16719 insertAtCursor : function(text)
16724 if(!this.activated){
16730 var r = this.doc.selection.createRange();
16741 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16745 // from jquery ui (MIT licenced)
16747 var win = this.win;
16749 if (win.getSelection && win.getSelection().getRangeAt) {
16750 range = win.getSelection().getRangeAt(0);
16751 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16752 range.insertNode(node);
16753 } else if (win.document.selection && win.document.selection.createRange) {
16754 // no firefox support
16755 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16756 win.document.selection.createRange().pasteHTML(txt);
16758 // no firefox support
16759 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16760 this.execCmd('InsertHTML', txt);
16769 mozKeyPress : function(e){
16771 var c = e.getCharCode(), cmd;
16774 c = String.fromCharCode(c).toLowerCase();
16788 this.cleanUpPaste.defer(100, this);
16796 e.preventDefault();
16804 fixKeys : function(){ // load time branching for fastest keydown performance
16806 return function(e){
16807 var k = e.getKey(), r;
16810 r = this.doc.selection.createRange();
16813 r.pasteHTML('    ');
16820 r = this.doc.selection.createRange();
16822 var target = r.parentElement();
16823 if(!target || target.tagName.toLowerCase() != 'li'){
16825 r.pasteHTML('<br />');
16831 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16832 this.cleanUpPaste.defer(100, this);
16838 }else if(Roo.isOpera){
16839 return function(e){
16840 var k = e.getKey();
16844 this.execCmd('InsertHTML','    ');
16847 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16848 this.cleanUpPaste.defer(100, this);
16853 }else if(Roo.isSafari){
16854 return function(e){
16855 var k = e.getKey();
16859 this.execCmd('InsertText','\t');
16863 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16864 this.cleanUpPaste.defer(100, this);
16872 getAllAncestors: function()
16874 var p = this.getSelectedNode();
16877 a.push(p); // push blank onto stack..
16878 p = this.getParentElement();
16882 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16886 a.push(this.doc.body);
16890 lastSelNode : false,
16893 getSelection : function()
16895 this.assignDocWin();
16896 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16899 getSelectedNode: function()
16901 // this may only work on Gecko!!!
16903 // should we cache this!!!!
16908 var range = this.createRange(this.getSelection()).cloneRange();
16911 var parent = range.parentElement();
16913 var testRange = range.duplicate();
16914 testRange.moveToElementText(parent);
16915 if (testRange.inRange(range)) {
16918 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16921 parent = parent.parentElement;
16926 // is ancestor a text element.
16927 var ac = range.commonAncestorContainer;
16928 if (ac.nodeType == 3) {
16929 ac = ac.parentNode;
16932 var ar = ac.childNodes;
16935 var other_nodes = [];
16936 var has_other_nodes = false;
16937 for (var i=0;i<ar.length;i++) {
16938 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16941 // fullly contained node.
16943 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16948 // probably selected..
16949 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16950 other_nodes.push(ar[i]);
16954 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16959 has_other_nodes = true;
16961 if (!nodes.length && other_nodes.length) {
16962 nodes= other_nodes;
16964 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16970 createRange: function(sel)
16972 // this has strange effects when using with
16973 // top toolbar - not sure if it's a great idea.
16974 //this.editor.contentWindow.focus();
16975 if (typeof sel != "undefined") {
16977 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16979 return this.doc.createRange();
16982 return this.doc.createRange();
16985 getParentElement: function()
16988 this.assignDocWin();
16989 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16991 var range = this.createRange(sel);
16994 var p = range.commonAncestorContainer;
16995 while (p.nodeType == 3) { // text node
17006 * Range intersection.. the hard stuff...
17010 * [ -- selected range --- ]
17014 * if end is before start or hits it. fail.
17015 * if start is after end or hits it fail.
17017 * if either hits (but other is outside. - then it's not
17023 // @see http://www.thismuchiknow.co.uk/?p=64.
17024 rangeIntersectsNode : function(range, node)
17026 var nodeRange = node.ownerDocument.createRange();
17028 nodeRange.selectNode(node);
17030 nodeRange.selectNodeContents(node);
17033 var rangeStartRange = range.cloneRange();
17034 rangeStartRange.collapse(true);
17036 var rangeEndRange = range.cloneRange();
17037 rangeEndRange.collapse(false);
17039 var nodeStartRange = nodeRange.cloneRange();
17040 nodeStartRange.collapse(true);
17042 var nodeEndRange = nodeRange.cloneRange();
17043 nodeEndRange.collapse(false);
17045 return rangeStartRange.compareBoundaryPoints(
17046 Range.START_TO_START, nodeEndRange) == -1 &&
17047 rangeEndRange.compareBoundaryPoints(
17048 Range.START_TO_START, nodeStartRange) == 1;
17052 rangeCompareNode : function(range, node)
17054 var nodeRange = node.ownerDocument.createRange();
17056 nodeRange.selectNode(node);
17058 nodeRange.selectNodeContents(node);
17062 range.collapse(true);
17064 nodeRange.collapse(true);
17066 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17067 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17069 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17071 var nodeIsBefore = ss == 1;
17072 var nodeIsAfter = ee == -1;
17074 if (nodeIsBefore && nodeIsAfter)
17076 if (!nodeIsBefore && nodeIsAfter)
17077 return 1; //right trailed.
17079 if (nodeIsBefore && !nodeIsAfter)
17080 return 2; // left trailed.
17085 // private? - in a new class?
17086 cleanUpPaste : function()
17088 // cleans up the whole document..
17089 Roo.log('cleanuppaste');
17091 this.cleanUpChildren(this.doc.body);
17092 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17093 if (clean != this.doc.body.innerHTML) {
17094 this.doc.body.innerHTML = clean;
17099 cleanWordChars : function(input) {// change the chars to hex code
17100 var he = Roo.HtmlEditorCore;
17102 var output = input;
17103 Roo.each(he.swapCodes, function(sw) {
17104 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17106 output = output.replace(swapper, sw[1]);
17113 cleanUpChildren : function (n)
17115 if (!n.childNodes.length) {
17118 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17119 this.cleanUpChild(n.childNodes[i]);
17126 cleanUpChild : function (node)
17129 //console.log(node);
17130 if (node.nodeName == "#text") {
17131 // clean up silly Windows -- stuff?
17134 if (node.nodeName == "#comment") {
17135 node.parentNode.removeChild(node);
17136 // clean up silly Windows -- stuff?
17140 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17142 node.parentNode.removeChild(node);
17147 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17149 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17150 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17152 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17153 // remove_keep_children = true;
17156 if (remove_keep_children) {
17157 this.cleanUpChildren(node);
17158 // inserts everything just before this node...
17159 while (node.childNodes.length) {
17160 var cn = node.childNodes[0];
17161 node.removeChild(cn);
17162 node.parentNode.insertBefore(cn, node);
17164 node.parentNode.removeChild(node);
17168 if (!node.attributes || !node.attributes.length) {
17169 this.cleanUpChildren(node);
17173 function cleanAttr(n,v)
17176 if (v.match(/^\./) || v.match(/^\//)) {
17179 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17182 if (v.match(/^#/)) {
17185 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17186 node.removeAttribute(n);
17190 function cleanStyle(n,v)
17192 if (v.match(/expression/)) { //XSS?? should we even bother..
17193 node.removeAttribute(n);
17196 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17197 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17200 var parts = v.split(/;/);
17203 Roo.each(parts, function(p) {
17204 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17208 var l = p.split(':').shift().replace(/\s+/g,'');
17209 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17211 if ( cblack.indexOf(l) > -1) {
17212 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17213 //node.removeAttribute(n);
17217 // only allow 'c whitelisted system attributes'
17218 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17219 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17220 //node.removeAttribute(n);
17230 if (clean.length) {
17231 node.setAttribute(n, clean.join(';'));
17233 node.removeAttribute(n);
17239 for (var i = node.attributes.length-1; i > -1 ; i--) {
17240 var a = node.attributes[i];
17243 if (a.name.toLowerCase().substr(0,2)=='on') {
17244 node.removeAttribute(a.name);
17247 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17248 node.removeAttribute(a.name);
17251 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17252 cleanAttr(a.name,a.value); // fixme..
17255 if (a.name == 'style') {
17256 cleanStyle(a.name,a.value);
17259 /// clean up MS crap..
17260 // tecnically this should be a list of valid class'es..
17263 if (a.name == 'class') {
17264 if (a.value.match(/^Mso/)) {
17265 node.className = '';
17268 if (a.value.match(/body/)) {
17269 node.className = '';
17280 this.cleanUpChildren(node);
17285 * Clean up MS wordisms...
17287 cleanWord : function(node)
17290 var cleanWordChildren = function()
17292 if (!node.childNodes.length) {
17295 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17296 _t.cleanWord(node.childNodes[i]);
17302 this.cleanWord(this.doc.body);
17305 if (node.nodeName == "#text") {
17306 // clean up silly Windows -- stuff?
17309 if (node.nodeName == "#comment") {
17310 node.parentNode.removeChild(node);
17311 // clean up silly Windows -- stuff?
17315 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17316 node.parentNode.removeChild(node);
17320 // remove - but keep children..
17321 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17322 while (node.childNodes.length) {
17323 var cn = node.childNodes[0];
17324 node.removeChild(cn);
17325 node.parentNode.insertBefore(cn, node);
17327 node.parentNode.removeChild(node);
17328 cleanWordChildren();
17332 if (node.className.length) {
17334 var cn = node.className.split(/\W+/);
17336 Roo.each(cn, function(cls) {
17337 if (cls.match(/Mso[a-zA-Z]+/)) {
17342 node.className = cna.length ? cna.join(' ') : '';
17344 node.removeAttribute("class");
17348 if (node.hasAttribute("lang")) {
17349 node.removeAttribute("lang");
17352 if (node.hasAttribute("style")) {
17354 var styles = node.getAttribute("style").split(";");
17356 Roo.each(styles, function(s) {
17357 if (!s.match(/:/)) {
17360 var kv = s.split(":");
17361 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17364 // what ever is left... we allow.
17367 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17368 if (!nstyle.length) {
17369 node.removeAttribute('style');
17373 cleanWordChildren();
17377 domToHTML : function(currentElement, depth, nopadtext) {
17379 depth = depth || 0;
17380 nopadtext = nopadtext || false;
17382 if (!currentElement) {
17383 return this.domToHTML(this.doc.body);
17386 //Roo.log(currentElement);
17388 var allText = false;
17389 var nodeName = currentElement.nodeName;
17390 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17392 if (nodeName == '#text') {
17393 return currentElement.nodeValue;
17398 if (nodeName != 'BODY') {
17401 // Prints the node tagName, such as <A>, <IMG>, etc
17404 for(i = 0; i < currentElement.attributes.length;i++) {
17406 var aname = currentElement.attributes.item(i).name;
17407 if (!currentElement.attributes.item(i).value.length) {
17410 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17413 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17422 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17425 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17430 // Traverse the tree
17432 var currentElementChild = currentElement.childNodes.item(i);
17433 var allText = true;
17434 var innerHTML = '';
17436 while (currentElementChild) {
17437 // Formatting code (indent the tree so it looks nice on the screen)
17438 var nopad = nopadtext;
17439 if (lastnode == 'SPAN') {
17443 if (currentElementChild.nodeName == '#text') {
17444 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17445 if (!nopad && toadd.length > 80) {
17446 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17448 innerHTML += toadd;
17451 currentElementChild = currentElement.childNodes.item(i);
17457 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17459 // Recursively traverse the tree structure of the child node
17460 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17461 lastnode = currentElementChild.nodeName;
17463 currentElementChild=currentElement.childNodes.item(i);
17469 // The remaining code is mostly for formatting the tree
17470 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17475 ret+= "</"+tagName+">";
17481 // hide stuff that is not compatible
17495 * @event specialkey
17499 * @cfg {String} fieldClass @hide
17502 * @cfg {String} focusClass @hide
17505 * @cfg {String} autoCreate @hide
17508 * @cfg {String} inputType @hide
17511 * @cfg {String} invalidClass @hide
17514 * @cfg {String} invalidText @hide
17517 * @cfg {String} msgFx @hide
17520 * @cfg {String} validateOnBlur @hide
17524 Roo.HtmlEditorCore.white = [
17525 'area', 'br', 'img', 'input', 'hr', 'wbr',
17527 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17528 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17529 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17530 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17531 'table', 'ul', 'xmp',
17533 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17536 'dir', 'menu', 'ol', 'ul', 'dl',
17542 Roo.HtmlEditorCore.black = [
17543 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17545 'base', 'basefont', 'bgsound', 'blink', 'body',
17546 'frame', 'frameset', 'head', 'html', 'ilayer',
17547 'iframe', 'layer', 'link', 'meta', 'object',
17548 'script', 'style' ,'title', 'xml' // clean later..
17550 Roo.HtmlEditorCore.clean = [
17551 'script', 'style', 'title', 'xml'
17553 Roo.HtmlEditorCore.remove = [
17558 Roo.HtmlEditorCore.ablack = [
17562 Roo.HtmlEditorCore.aclean = [
17563 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17567 Roo.HtmlEditorCore.pwhite= [
17568 'http', 'https', 'mailto'
17571 // white listed style attributes.
17572 Roo.HtmlEditorCore.cwhite= [
17573 // 'text-align', /// default is to allow most things..
17579 // black listed style attributes.
17580 Roo.HtmlEditorCore.cblack= [
17581 // 'font-size' -- this can be set by the project
17585 Roo.HtmlEditorCore.swapCodes =[
17604 * @class Roo.bootstrap.HtmlEditor
17605 * @extends Roo.bootstrap.TextArea
17606 * Bootstrap HtmlEditor class
17609 * Create a new HtmlEditor
17610 * @param {Object} config The config object
17613 Roo.bootstrap.HtmlEditor = function(config){
17614 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17615 if (!this.toolbars) {
17616 this.toolbars = [];
17618 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17621 * @event initialize
17622 * Fires when the editor is fully initialized (including the iframe)
17623 * @param {HtmlEditor} this
17628 * Fires when the editor is first receives the focus. Any insertion must wait
17629 * until after this event.
17630 * @param {HtmlEditor} this
17634 * @event beforesync
17635 * Fires before the textarea is updated with content from the editor iframe. Return false
17636 * to cancel the sync.
17637 * @param {HtmlEditor} this
17638 * @param {String} html
17642 * @event beforepush
17643 * Fires before the iframe editor is updated with content from the textarea. Return false
17644 * to cancel the push.
17645 * @param {HtmlEditor} this
17646 * @param {String} html
17651 * Fires when the textarea is updated with content from the editor iframe.
17652 * @param {HtmlEditor} this
17653 * @param {String} html
17658 * Fires when the iframe editor is updated with content from the textarea.
17659 * @param {HtmlEditor} this
17660 * @param {String} html
17664 * @event editmodechange
17665 * Fires when the editor switches edit modes
17666 * @param {HtmlEditor} this
17667 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17669 editmodechange: true,
17671 * @event editorevent
17672 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17673 * @param {HtmlEditor} this
17677 * @event firstfocus
17678 * Fires when on first focus - needed by toolbars..
17679 * @param {HtmlEditor} this
17684 * Auto save the htmlEditor value as a file into Events
17685 * @param {HtmlEditor} this
17689 * @event savedpreview
17690 * preview the saved version of htmlEditor
17691 * @param {HtmlEditor} this
17698 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17702 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17707 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17712 * @cfg {Number} height (in pixels)
17716 * @cfg {Number} width (in pixels)
17721 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17724 stylesheets: false,
17729 // private properties
17730 validationEvent : false,
17732 initialized : false,
17735 onFocus : Roo.emptyFn,
17737 hideMode:'offsets',
17740 tbContainer : false,
17742 toolbarContainer :function() {
17743 return this.wrap.select('.x-html-editor-tb',true).first();
17747 * Protected method that will not generally be called directly. It
17748 * is called when the editor creates its toolbar. Override this method if you need to
17749 * add custom toolbar buttons.
17750 * @param {HtmlEditor} editor
17752 createToolbar : function(){
17754 Roo.log("create toolbars");
17756 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17757 this.toolbars[0].render(this.toolbarContainer());
17761 // if (!editor.toolbars || !editor.toolbars.length) {
17762 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17765 // for (var i =0 ; i < editor.toolbars.length;i++) {
17766 // editor.toolbars[i] = Roo.factory(
17767 // typeof(editor.toolbars[i]) == 'string' ?
17768 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17769 // Roo.bootstrap.HtmlEditor);
17770 // editor.toolbars[i].init(editor);
17776 onRender : function(ct, position)
17778 // Roo.log("Call onRender: " + this.xtype);
17780 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17782 this.wrap = this.inputEl().wrap({
17783 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17786 this.editorcore.onRender(ct, position);
17788 if (this.resizable) {
17789 this.resizeEl = new Roo.Resizable(this.wrap, {
17793 minHeight : this.height,
17794 height: this.height,
17795 handles : this.resizable,
17798 resize : function(r, w, h) {
17799 _t.onResize(w,h); // -something
17805 this.createToolbar(this);
17808 if(!this.width && this.resizable){
17809 this.setSize(this.wrap.getSize());
17811 if (this.resizeEl) {
17812 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17813 // should trigger onReize..
17819 onResize : function(w, h)
17821 Roo.log('resize: ' +w + ',' + h );
17822 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17826 if(this.inputEl() ){
17827 if(typeof w == 'number'){
17828 var aw = w - this.wrap.getFrameWidth('lr');
17829 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17832 if(typeof h == 'number'){
17833 var tbh = -11; // fixme it needs to tool bar size!
17834 for (var i =0; i < this.toolbars.length;i++) {
17835 // fixme - ask toolbars for heights?
17836 tbh += this.toolbars[i].el.getHeight();
17837 //if (this.toolbars[i].footer) {
17838 // tbh += this.toolbars[i].footer.el.getHeight();
17846 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17847 ah -= 5; // knock a few pixes off for look..
17848 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17852 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17853 this.editorcore.onResize(ew,eh);
17858 * Toggles the editor between standard and source edit mode.
17859 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17861 toggleSourceEdit : function(sourceEditMode)
17863 this.editorcore.toggleSourceEdit(sourceEditMode);
17865 if(this.editorcore.sourceEditMode){
17866 Roo.log('editor - showing textarea');
17869 // Roo.log(this.syncValue());
17871 this.inputEl().removeClass(['hide', 'x-hidden']);
17872 this.inputEl().dom.removeAttribute('tabIndex');
17873 this.inputEl().focus();
17875 Roo.log('editor - hiding textarea');
17877 // Roo.log(this.pushValue());
17880 this.inputEl().addClass(['hide', 'x-hidden']);
17881 this.inputEl().dom.setAttribute('tabIndex', -1);
17882 //this.deferFocus();
17885 if(this.resizable){
17886 this.setSize(this.wrap.getSize());
17889 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17892 // private (for BoxComponent)
17893 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17895 // private (for BoxComponent)
17896 getResizeEl : function(){
17900 // private (for BoxComponent)
17901 getPositionEl : function(){
17906 initEvents : function(){
17907 this.originalValue = this.getValue();
17911 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17914 // markInvalid : Roo.emptyFn,
17916 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17919 // clearInvalid : Roo.emptyFn,
17921 setValue : function(v){
17922 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17923 this.editorcore.pushValue();
17928 deferFocus : function(){
17929 this.focus.defer(10, this);
17933 focus : function(){
17934 this.editorcore.focus();
17940 onDestroy : function(){
17946 for (var i =0; i < this.toolbars.length;i++) {
17947 // fixme - ask toolbars for heights?
17948 this.toolbars[i].onDestroy();
17951 this.wrap.dom.innerHTML = '';
17952 this.wrap.remove();
17957 onFirstFocus : function(){
17958 //Roo.log("onFirstFocus");
17959 this.editorcore.onFirstFocus();
17960 for (var i =0; i < this.toolbars.length;i++) {
17961 this.toolbars[i].onFirstFocus();
17967 syncValue : function()
17969 this.editorcore.syncValue();
17972 pushValue : function()
17974 this.editorcore.pushValue();
17978 // hide stuff that is not compatible
17992 * @event specialkey
17996 * @cfg {String} fieldClass @hide
17999 * @cfg {String} focusClass @hide
18002 * @cfg {String} autoCreate @hide
18005 * @cfg {String} inputType @hide
18008 * @cfg {String} invalidClass @hide
18011 * @cfg {String} invalidText @hide
18014 * @cfg {String} msgFx @hide
18017 * @cfg {String} validateOnBlur @hide
18026 Roo.namespace('Roo.bootstrap.htmleditor');
18028 * @class Roo.bootstrap.HtmlEditorToolbar1
18033 new Roo.bootstrap.HtmlEditor({
18036 new Roo.bootstrap.HtmlEditorToolbar1({
18037 disable : { fonts: 1 , format: 1, ..., ... , ...],
18043 * @cfg {Object} disable List of elements to disable..
18044 * @cfg {Array} btns List of additional buttons.
18048 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18051 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18054 Roo.apply(this, config);
18056 // default disabled, based on 'good practice'..
18057 this.disable = this.disable || {};
18058 Roo.applyIf(this.disable, {
18061 specialElements : true
18063 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18065 this.editor = config.editor;
18066 this.editorcore = config.editor.editorcore;
18068 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18070 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18071 // dont call parent... till later.
18073 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18078 editorcore : false,
18083 "h1","h2","h3","h4","h5","h6",
18085 "abbr", "acronym", "address", "cite", "samp", "var",
18089 onRender : function(ct, position)
18091 // Roo.log("Call onRender: " + this.xtype);
18093 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18095 this.el.dom.style.marginBottom = '0';
18097 var editorcore = this.editorcore;
18098 var editor= this.editor;
18101 var btn = function(id,cmd , toggle, handler){
18103 var event = toggle ? 'toggle' : 'click';
18108 xns: Roo.bootstrap,
18111 enableToggle:toggle !== false,
18113 pressed : toggle ? false : null,
18116 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18117 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18126 xns: Roo.bootstrap,
18127 glyphicon : 'font',
18131 xns: Roo.bootstrap,
18135 Roo.each(this.formats, function(f) {
18136 style.menu.items.push({
18138 xns: Roo.bootstrap,
18139 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18144 editorcore.insertTag(this.tagname);
18151 children.push(style);
18154 btn('bold',false,true);
18155 btn('italic',false,true);
18156 btn('align-left', 'justifyleft',true);
18157 btn('align-center', 'justifycenter',true);
18158 btn('align-right' , 'justifyright',true);
18159 btn('link', false, false, function(btn) {
18160 //Roo.log("create link?");
18161 var url = prompt(this.createLinkText, this.defaultLinkValue);
18162 if(url && url != 'http:/'+'/'){
18163 this.editorcore.relayCmd('createlink', url);
18166 btn('list','insertunorderedlist',true);
18167 btn('pencil', false,true, function(btn){
18170 this.toggleSourceEdit(btn.pressed);
18176 xns: Roo.bootstrap,
18181 xns: Roo.bootstrap,
18186 cog.menu.items.push({
18188 xns: Roo.bootstrap,
18189 html : Clean styles,
18194 editorcore.insertTag(this.tagname);
18203 this.xtype = 'NavSimplebar';
18205 for(var i=0;i< children.length;i++) {
18207 this.buttons.add(this.addxtypeChild(children[i]));
18211 editor.on('editorevent', this.updateToolbar, this);
18213 onBtnClick : function(id)
18215 this.editorcore.relayCmd(id);
18216 this.editorcore.focus();
18220 * Protected method that will not generally be called directly. It triggers
18221 * a toolbar update by reading the markup state of the current selection in the editor.
18223 updateToolbar: function(){
18225 if(!this.editorcore.activated){
18226 this.editor.onFirstFocus(); // is this neeed?
18230 var btns = this.buttons;
18231 var doc = this.editorcore.doc;
18232 btns.get('bold').setActive(doc.queryCommandState('bold'));
18233 btns.get('italic').setActive(doc.queryCommandState('italic'));
18234 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18236 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18237 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18238 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18240 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18241 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18244 var ans = this.editorcore.getAllAncestors();
18245 if (this.formatCombo) {
18248 var store = this.formatCombo.store;
18249 this.formatCombo.setValue("");
18250 for (var i =0; i < ans.length;i++) {
18251 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18253 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18261 // hides menus... - so this cant be on a menu...
18262 Roo.bootstrap.MenuMgr.hideAll();
18264 Roo.bootstrap.MenuMgr.hideAll();
18265 //this.editorsyncValue();
18267 onFirstFocus: function() {
18268 this.buttons.each(function(item){
18272 toggleSourceEdit : function(sourceEditMode){
18275 if(sourceEditMode){
18276 Roo.log("disabling buttons");
18277 this.buttons.each( function(item){
18278 if(item.cmd != 'pencil'){
18284 Roo.log("enabling buttons");
18285 if(this.editorcore.initialized){
18286 this.buttons.each( function(item){
18292 Roo.log("calling toggole on editor");
18293 // tell the editor that it's been pressed..
18294 this.editor.toggleSourceEdit(sourceEditMode);
18304 * @class Roo.bootstrap.Table.AbstractSelectionModel
18305 * @extends Roo.util.Observable
18306 * Abstract base class for grid SelectionModels. It provides the interface that should be
18307 * implemented by descendant classes. This class should not be directly instantiated.
18310 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18311 this.locked = false;
18312 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18316 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18317 /** @ignore Called by the grid automatically. Do not call directly. */
18318 init : function(grid){
18324 * Locks the selections.
18327 this.locked = true;
18331 * Unlocks the selections.
18333 unlock : function(){
18334 this.locked = false;
18338 * Returns true if the selections are locked.
18339 * @return {Boolean}
18341 isLocked : function(){
18342 return this.locked;
18346 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18347 * @class Roo.bootstrap.Table.RowSelectionModel
18348 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18349 * It supports multiple selections and keyboard selection/navigation.
18351 * @param {Object} config
18354 Roo.bootstrap.Table.RowSelectionModel = function(config){
18355 Roo.apply(this, config);
18356 this.selections = new Roo.util.MixedCollection(false, function(o){
18361 this.lastActive = false;
18365 * @event selectionchange
18366 * Fires when the selection changes
18367 * @param {SelectionModel} this
18369 "selectionchange" : true,
18371 * @event afterselectionchange
18372 * Fires after the selection changes (eg. by key press or clicking)
18373 * @param {SelectionModel} this
18375 "afterselectionchange" : true,
18377 * @event beforerowselect
18378 * Fires when a row is selected being selected, return false to cancel.
18379 * @param {SelectionModel} this
18380 * @param {Number} rowIndex The selected index
18381 * @param {Boolean} keepExisting False if other selections will be cleared
18383 "beforerowselect" : true,
18386 * Fires when a row is selected.
18387 * @param {SelectionModel} this
18388 * @param {Number} rowIndex The selected index
18389 * @param {Roo.data.Record} r The record
18391 "rowselect" : true,
18393 * @event rowdeselect
18394 * Fires when a row is deselected.
18395 * @param {SelectionModel} this
18396 * @param {Number} rowIndex The selected index
18398 "rowdeselect" : true
18400 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18401 this.locked = false;
18404 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18406 * @cfg {Boolean} singleSelect
18407 * True to allow selection of only one row at a time (defaults to false)
18409 singleSelect : false,
18412 initEvents : function(){
18414 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18415 this.grid.on("mousedown", this.handleMouseDown, this);
18416 }else{ // allow click to work like normal
18417 this.grid.on("rowclick", this.handleDragableRowClick, this);
18420 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18421 "up" : function(e){
18423 this.selectPrevious(e.shiftKey);
18424 }else if(this.last !== false && this.lastActive !== false){
18425 var last = this.last;
18426 this.selectRange(this.last, this.lastActive-1);
18427 this.grid.getView().focusRow(this.lastActive);
18428 if(last !== false){
18432 this.selectFirstRow();
18434 this.fireEvent("afterselectionchange", this);
18436 "down" : function(e){
18438 this.selectNext(e.shiftKey);
18439 }else if(this.last !== false && this.lastActive !== false){
18440 var last = this.last;
18441 this.selectRange(this.last, this.lastActive+1);
18442 this.grid.getView().focusRow(this.lastActive);
18443 if(last !== false){
18447 this.selectFirstRow();
18449 this.fireEvent("afterselectionchange", this);
18454 var view = this.grid.view;
18455 view.on("refresh", this.onRefresh, this);
18456 view.on("rowupdated", this.onRowUpdated, this);
18457 view.on("rowremoved", this.onRemove, this);
18461 onRefresh : function(){
18462 var ds = this.grid.dataSource, i, v = this.grid.view;
18463 var s = this.selections;
18464 s.each(function(r){
18465 if((i = ds.indexOfId(r.id)) != -1){
18474 onRemove : function(v, index, r){
18475 this.selections.remove(r);
18479 onRowUpdated : function(v, index, r){
18480 if(this.isSelected(r)){
18481 v.onRowSelect(index);
18487 * @param {Array} records The records to select
18488 * @param {Boolean} keepExisting (optional) True to keep existing selections
18490 selectRecords : function(records, keepExisting){
18492 this.clearSelections();
18494 var ds = this.grid.dataSource;
18495 for(var i = 0, len = records.length; i < len; i++){
18496 this.selectRow(ds.indexOf(records[i]), true);
18501 * Gets the number of selected rows.
18504 getCount : function(){
18505 return this.selections.length;
18509 * Selects the first row in the grid.
18511 selectFirstRow : function(){
18516 * Select the last row.
18517 * @param {Boolean} keepExisting (optional) True to keep existing selections
18519 selectLastRow : function(keepExisting){
18520 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18524 * Selects the row immediately following the last selected row.
18525 * @param {Boolean} keepExisting (optional) True to keep existing selections
18527 selectNext : function(keepExisting){
18528 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18529 this.selectRow(this.last+1, keepExisting);
18530 this.grid.getView().focusRow(this.last);
18535 * Selects the row that precedes the last selected row.
18536 * @param {Boolean} keepExisting (optional) True to keep existing selections
18538 selectPrevious : function(keepExisting){
18540 this.selectRow(this.last-1, keepExisting);
18541 this.grid.getView().focusRow(this.last);
18546 * Returns the selected records
18547 * @return {Array} Array of selected records
18549 getSelections : function(){
18550 return [].concat(this.selections.items);
18554 * Returns the first selected record.
18557 getSelected : function(){
18558 return this.selections.itemAt(0);
18563 * Clears all selections.
18565 clearSelections : function(fast){
18566 if(this.locked) return;
18568 var ds = this.grid.dataSource;
18569 var s = this.selections;
18570 s.each(function(r){
18571 this.deselectRow(ds.indexOfId(r.id));
18575 this.selections.clear();
18582 * Selects all rows.
18584 selectAll : function(){
18585 if(this.locked) return;
18586 this.selections.clear();
18587 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18588 this.selectRow(i, true);
18593 * Returns True if there is a selection.
18594 * @return {Boolean}
18596 hasSelection : function(){
18597 return this.selections.length > 0;
18601 * Returns True if the specified row is selected.
18602 * @param {Number/Record} record The record or index of the record to check
18603 * @return {Boolean}
18605 isSelected : function(index){
18606 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18607 return (r && this.selections.key(r.id) ? true : false);
18611 * Returns True if the specified record id is selected.
18612 * @param {String} id The id of record to check
18613 * @return {Boolean}
18615 isIdSelected : function(id){
18616 return (this.selections.key(id) ? true : false);
18620 handleMouseDown : function(e, t){
18621 var view = this.grid.getView(), rowIndex;
18622 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18625 if(e.shiftKey && this.last !== false){
18626 var last = this.last;
18627 this.selectRange(last, rowIndex, e.ctrlKey);
18628 this.last = last; // reset the last
18629 view.focusRow(rowIndex);
18631 var isSelected = this.isSelected(rowIndex);
18632 if(e.button !== 0 && isSelected){
18633 view.focusRow(rowIndex);
18634 }else if(e.ctrlKey && isSelected){
18635 this.deselectRow(rowIndex);
18636 }else if(!isSelected){
18637 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18638 view.focusRow(rowIndex);
18641 this.fireEvent("afterselectionchange", this);
18644 handleDragableRowClick : function(grid, rowIndex, e)
18646 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18647 this.selectRow(rowIndex, false);
18648 grid.view.focusRow(rowIndex);
18649 this.fireEvent("afterselectionchange", this);
18654 * Selects multiple rows.
18655 * @param {Array} rows Array of the indexes of the row to select
18656 * @param {Boolean} keepExisting (optional) True to keep existing selections
18658 selectRows : function(rows, keepExisting){
18660 this.clearSelections();
18662 for(var i = 0, len = rows.length; i < len; i++){
18663 this.selectRow(rows[i], true);
18668 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18669 * @param {Number} startRow The index of the first row in the range
18670 * @param {Number} endRow The index of the last row in the range
18671 * @param {Boolean} keepExisting (optional) True to retain existing selections
18673 selectRange : function(startRow, endRow, keepExisting){
18674 if(this.locked) return;
18676 this.clearSelections();
18678 if(startRow <= endRow){
18679 for(var i = startRow; i <= endRow; i++){
18680 this.selectRow(i, true);
18683 for(var i = startRow; i >= endRow; i--){
18684 this.selectRow(i, true);
18690 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18691 * @param {Number} startRow The index of the first row in the range
18692 * @param {Number} endRow The index of the last row in the range
18694 deselectRange : function(startRow, endRow, preventViewNotify){
18695 if(this.locked) return;
18696 for(var i = startRow; i <= endRow; i++){
18697 this.deselectRow(i, preventViewNotify);
18703 * @param {Number} row The index of the row to select
18704 * @param {Boolean} keepExisting (optional) True to keep existing selections
18706 selectRow : function(index, keepExisting, preventViewNotify){
18707 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18708 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18709 if(!keepExisting || this.singleSelect){
18710 this.clearSelections();
18712 var r = this.grid.dataSource.getAt(index);
18713 this.selections.add(r);
18714 this.last = this.lastActive = index;
18715 if(!preventViewNotify){
18716 this.grid.getView().onRowSelect(index);
18718 this.fireEvent("rowselect", this, index, r);
18719 this.fireEvent("selectionchange", this);
18725 * @param {Number} row The index of the row to deselect
18727 deselectRow : function(index, preventViewNotify){
18728 if(this.locked) return;
18729 if(this.last == index){
18732 if(this.lastActive == index){
18733 this.lastActive = false;
18735 var r = this.grid.dataSource.getAt(index);
18736 this.selections.remove(r);
18737 if(!preventViewNotify){
18738 this.grid.getView().onRowDeselect(index);
18740 this.fireEvent("rowdeselect", this, index);
18741 this.fireEvent("selectionchange", this);
18745 restoreLast : function(){
18747 this.last = this._last;
18752 acceptsNav : function(row, col, cm){
18753 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18757 onEditorKey : function(field, e){
18758 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18763 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18765 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18767 }else if(k == e.ENTER && !e.ctrlKey){
18771 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18773 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18775 }else if(k == e.ESC){
18779 g.startEditing(newCell[0], newCell[1]);
18784 * Ext JS Library 1.1.1
18785 * Copyright(c) 2006-2007, Ext JS, LLC.
18787 * Originally Released Under LGPL - original licence link has changed is not relivant.
18790 * <script type="text/javascript">
18794 * @class Roo.bootstrap.PagingToolbar
18796 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18798 * Create a new PagingToolbar
18799 * @param {Object} config The config object
18801 Roo.bootstrap.PagingToolbar = function(config)
18803 // old args format still supported... - xtype is prefered..
18804 // created from xtype...
18805 var ds = config.dataSource;
18806 this.toolbarItems = [];
18807 if (config.items) {
18808 this.toolbarItems = config.items;
18809 // config.items = [];
18812 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18819 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18823 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18825 * @cfg {Roo.data.Store} dataSource
18826 * The underlying data store providing the paged data
18829 * @cfg {String/HTMLElement/Element} container
18830 * container The id or element that will contain the toolbar
18833 * @cfg {Boolean} displayInfo
18834 * True to display the displayMsg (defaults to false)
18837 * @cfg {Number} pageSize
18838 * The number of records to display per page (defaults to 20)
18842 * @cfg {String} displayMsg
18843 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18845 displayMsg : 'Displaying {0} - {1} of {2}',
18847 * @cfg {String} emptyMsg
18848 * The message to display when no records are found (defaults to "No data to display")
18850 emptyMsg : 'No data to display',
18852 * Customizable piece of the default paging text (defaults to "Page")
18855 beforePageText : "Page",
18857 * Customizable piece of the default paging text (defaults to "of %0")
18860 afterPageText : "of {0}",
18862 * Customizable piece of the default paging text (defaults to "First Page")
18865 firstText : "First Page",
18867 * Customizable piece of the default paging text (defaults to "Previous Page")
18870 prevText : "Previous Page",
18872 * Customizable piece of the default paging text (defaults to "Next Page")
18875 nextText : "Next Page",
18877 * Customizable piece of the default paging text (defaults to "Last Page")
18880 lastText : "Last Page",
18882 * Customizable piece of the default paging text (defaults to "Refresh")
18885 refreshText : "Refresh",
18889 onRender : function(ct, position)
18891 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18892 this.navgroup.parentId = this.id;
18893 this.navgroup.onRender(this.el, null);
18894 // add the buttons to the navgroup
18896 if(this.displayInfo){
18897 Roo.log(this.el.select('ul.navbar-nav',true).first());
18898 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18899 this.displayEl = this.el.select('.x-paging-info', true).first();
18900 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18901 // this.displayEl = navel.el.select('span',true).first();
18907 Roo.each(_this.buttons, function(e){
18908 Roo.factory(e).onRender(_this.el, null);
18912 Roo.each(_this.toolbarItems, function(e) {
18913 _this.navgroup.addItem(e);
18916 this.first = this.navgroup.addItem({
18917 tooltip: this.firstText,
18919 icon : 'fa fa-backward',
18921 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18924 this.prev = this.navgroup.addItem({
18925 tooltip: this.prevText,
18927 icon : 'fa fa-step-backward',
18929 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18931 //this.addSeparator();
18934 var field = this.navgroup.addItem( {
18936 cls : 'x-paging-position',
18938 html : this.beforePageText +
18939 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18940 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18943 this.field = field.el.select('input', true).first();
18944 this.field.on("keydown", this.onPagingKeydown, this);
18945 this.field.on("focus", function(){this.dom.select();});
18948 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18949 //this.field.setHeight(18);
18950 //this.addSeparator();
18951 this.next = this.navgroup.addItem({
18952 tooltip: this.nextText,
18954 html : ' <i class="fa fa-step-forward">',
18956 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18958 this.last = this.navgroup.addItem({
18959 tooltip: this.lastText,
18960 icon : 'fa fa-forward',
18963 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18965 //this.addSeparator();
18966 this.loading = this.navgroup.addItem({
18967 tooltip: this.refreshText,
18968 icon: 'fa fa-refresh',
18970 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18976 updateInfo : function(){
18977 if(this.displayEl){
18978 var count = this.ds.getCount();
18979 var msg = count == 0 ?
18983 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18985 this.displayEl.update(msg);
18990 onLoad : function(ds, r, o){
18991 this.cursor = o.params ? o.params.start : 0;
18992 var d = this.getPageData(),
18996 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18997 this.field.dom.value = ap;
18998 this.first.setDisabled(ap == 1);
18999 this.prev.setDisabled(ap == 1);
19000 this.next.setDisabled(ap == ps);
19001 this.last.setDisabled(ap == ps);
19002 this.loading.enable();
19007 getPageData : function(){
19008 var total = this.ds.getTotalCount();
19011 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19012 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19017 onLoadError : function(){
19018 this.loading.enable();
19022 onPagingKeydown : function(e){
19023 var k = e.getKey();
19024 var d = this.getPageData();
19026 var v = this.field.dom.value, pageNum;
19027 if(!v || isNaN(pageNum = parseInt(v, 10))){
19028 this.field.dom.value = d.activePage;
19031 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19032 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19035 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))
19037 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19038 this.field.dom.value = pageNum;
19039 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19042 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19044 var v = this.field.dom.value, pageNum;
19045 var increment = (e.shiftKey) ? 10 : 1;
19046 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19048 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19049 this.field.dom.value = d.activePage;
19052 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19054 this.field.dom.value = parseInt(v, 10) + increment;
19055 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19056 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19063 beforeLoad : function(){
19065 this.loading.disable();
19070 onClick : function(which){
19077 ds.load({params:{start: 0, limit: this.pageSize}});
19080 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19083 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19086 var total = ds.getTotalCount();
19087 var extra = total % this.pageSize;
19088 var lastStart = extra ? (total - extra) : total-this.pageSize;
19089 ds.load({params:{start: lastStart, limit: this.pageSize}});
19092 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19098 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19099 * @param {Roo.data.Store} store The data store to unbind
19101 unbind : function(ds){
19102 ds.un("beforeload", this.beforeLoad, this);
19103 ds.un("load", this.onLoad, this);
19104 ds.un("loadexception", this.onLoadError, this);
19105 ds.un("remove", this.updateInfo, this);
19106 ds.un("add", this.updateInfo, this);
19107 this.ds = undefined;
19111 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19112 * @param {Roo.data.Store} store The data store to bind
19114 bind : function(ds){
19115 ds.on("beforeload", this.beforeLoad, this);
19116 ds.on("load", this.onLoad, this);
19117 ds.on("loadexception", this.onLoadError, this);
19118 ds.on("remove", this.updateInfo, this);
19119 ds.on("add", this.updateInfo, this);
19130 * @class Roo.bootstrap.MessageBar
19131 * @extends Roo.bootstrap.Component
19132 * Bootstrap MessageBar class
19133 * @cfg {String} html contents of the MessageBar
19134 * @cfg {String} weight (info | success | warning | danger) default info
19135 * @cfg {String} beforeClass insert the bar before the given class
19136 * @cfg {Boolean} closable (true | false) default false
19137 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19140 * Create a new Element
19141 * @param {Object} config The config object
19144 Roo.bootstrap.MessageBar = function(config){
19145 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19148 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19154 beforeClass: 'bootstrap-sticky-wrap',
19156 getAutoCreate : function(){
19160 cls: 'alert alert-dismissable alert-' + this.weight,
19165 html: this.html || ''
19171 cfg.cls += ' alert-messages-fixed';
19185 onRender : function(ct, position)
19187 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19190 var cfg = Roo.apply({}, this.getAutoCreate());
19194 cfg.cls += ' ' + this.cls;
19197 cfg.style = this.style;
19199 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19201 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19204 this.el.select('>button.close').on('click', this.hide, this);
19210 if (!this.rendered) {
19216 this.fireEvent('show', this);
19222 if (!this.rendered) {
19228 this.fireEvent('hide', this);
19231 update : function()
19233 // var e = this.el.dom.firstChild;
19235 // if(this.closable){
19236 // e = e.nextSibling;
19239 // e.data = this.html || '';
19241 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19257 * @class Roo.bootstrap.Graph
19258 * @extends Roo.bootstrap.Component
19259 * Bootstrap Graph class
19263 @cfg {String} graphtype bar | vbar | pie
19264 @cfg {number} g_x coodinator | centre x (pie)
19265 @cfg {number} g_y coodinator | centre y (pie)
19266 @cfg {number} g_r radius (pie)
19267 @cfg {number} g_height height of the chart (respected by all elements in the set)
19268 @cfg {number} g_width width of the chart (respected by all elements in the set)
19269 @cfg {Object} title The title of the chart
19272 -opts (object) options for the chart
19274 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19275 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19277 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.
19278 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19280 o stretch (boolean)
19282 -opts (object) options for the pie
19285 o startAngle (number)
19286 o endAngle (number)
19290 * Create a new Input
19291 * @param {Object} config The config object
19294 Roo.bootstrap.Graph = function(config){
19295 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19301 * The img click event for the img.
19302 * @param {Roo.EventObject} e
19308 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19319 //g_colors: this.colors,
19326 getAutoCreate : function(){
19337 onRender : function(ct,position){
19338 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19339 this.raphael = Raphael(this.el.dom);
19341 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19342 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19343 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19344 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19346 r.text(160, 10, "Single Series Chart").attr(txtattr);
19347 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19348 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19349 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19351 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19352 r.barchart(330, 10, 300, 220, data1);
19353 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19354 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19357 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19358 // r.barchart(30, 30, 560, 250, xdata, {
19359 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19360 // axis : "0 0 1 1",
19361 // axisxlabels : xdata
19362 // //yvalues : cols,
19365 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19367 // this.load(null,xdata,{
19368 // axis : "0 0 1 1",
19369 // axisxlabels : xdata
19374 load : function(graphtype,xdata,opts){
19375 this.raphael.clear();
19377 graphtype = this.graphtype;
19382 var r = this.raphael,
19383 fin = function () {
19384 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19386 fout = function () {
19387 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19389 pfin = function() {
19390 this.sector.stop();
19391 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19394 this.label[0].stop();
19395 this.label[0].attr({ r: 7.5 });
19396 this.label[1].attr({ "font-weight": 800 });
19399 pfout = function() {
19400 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19403 this.label[0].animate({ r: 5 }, 500, "bounce");
19404 this.label[1].attr({ "font-weight": 400 });
19410 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19413 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19416 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19417 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19419 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19426 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19431 setTitle: function(o)
19436 initEvents: function() {
19439 this.el.on('click', this.onClick, this);
19443 onClick : function(e)
19445 Roo.log('img onclick');
19446 this.fireEvent('click', this, e);
19458 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19461 * @class Roo.bootstrap.dash.NumberBox
19462 * @extends Roo.bootstrap.Component
19463 * Bootstrap NumberBox class
19464 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19465 * @cfg {String} headline Box headline
19466 * @cfg {String} content Box content
19467 * @cfg {String} icon Box icon
19468 * @cfg {String} footer Footer text
19469 * @cfg {String} fhref Footer href
19472 * Create a new NumberBox
19473 * @param {Object} config The config object
19477 Roo.bootstrap.dash.NumberBox = function(config){
19478 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19482 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19492 getAutoCreate : function(){
19496 cls : 'small-box bg-' + this.bgcolor,
19504 cls : 'roo-headline',
19505 html : this.headline
19509 cls : 'roo-content',
19510 html : this.content
19524 cls : 'ion ' + this.icon
19533 cls : 'small-box-footer',
19534 href : this.fhref || '#',
19538 cfg.cn.push(footer);
19545 onRender : function(ct,position){
19546 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19553 setHeadline: function (value)
19555 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19558 setFooter: function (value, href)
19560 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19563 this.el.select('a.small-box-footer',true).first().attr('href', href);
19568 setContent: function (value)
19570 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19573 initEvents: function()
19587 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19590 * @class Roo.bootstrap.dash.TabBox
19591 * @extends Roo.bootstrap.Component
19592 * Bootstrap TabBox class
19593 * @cfg {String} title Title of the TabBox
19594 * @cfg {String} icon Icon of the TabBox
19595 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19598 * Create a new TabBox
19599 * @param {Object} config The config object
19603 Roo.bootstrap.dash.TabBox = function(config){
19604 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19609 * When a pane is added
19610 * @param {Roo.bootstrap.dash.TabPane} pane
19617 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19623 getChildContainer : function()
19625 return this.el.select('.tab-content', true).first();
19628 getAutoCreate : function(){
19632 cls: 'pull-left header',
19640 cls: 'fa ' + this.icon
19647 cls: 'nav-tabs-custom',
19651 cls: 'nav nav-tabs pull-right',
19658 cls: 'tab-content no-padding',
19666 initEvents : function()
19668 //Roo.log('add add pane handler');
19669 this.on('addpane', this.onAddPane, this);
19672 * Updates the box title
19673 * @param {String} html to set the title to.
19675 setTitle : function(value)
19677 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19679 onAddPane : function(pane)
19681 //Roo.log('addpane');
19683 // tabs are rendere left to right..
19684 if(!this.showtabs){
19688 var ctr = this.el.select('.nav-tabs', true).first();
19691 var existing = ctr.select('.nav-tab',true);
19692 var qty = existing.getCount();;
19695 var tab = ctr.createChild({
19697 cls : 'nav-tab' + (qty ? '' : ' active'),
19705 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19708 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19710 pane.el.addClass('active');
19715 onTabClick : function(ev,un,ob,pane)
19717 //Roo.log('tab - prev default');
19718 ev.preventDefault();
19721 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19722 pane.tab.addClass('active');
19723 //Roo.log(pane.title);
19724 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19725 // technically we should have a deactivate event.. but maybe add later.
19726 // and it should not de-activate the selected tab...
19728 pane.el.addClass('active');
19729 pane.fireEvent('activate');
19744 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19746 * @class Roo.bootstrap.TabPane
19747 * @extends Roo.bootstrap.Component
19748 * Bootstrap TabPane class
19749 * @cfg {Boolean} active (false | true) Default false
19750 * @cfg {String} title title of panel
19754 * Create a new TabPane
19755 * @param {Object} config The config object
19758 Roo.bootstrap.dash.TabPane = function(config){
19759 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19763 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19768 // the tabBox that this is attached to.
19771 getAutoCreate : function()
19779 cfg.cls += ' active';
19784 initEvents : function()
19786 //Roo.log('trigger add pane handler');
19787 this.parent().fireEvent('addpane', this)
19791 * Updates the tab title
19792 * @param {String} html to set the title to.
19794 setTitle: function(str)
19800 this.tab.select('a', true).first().dom.innerHTML = str;
19817 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19820 * @class Roo.bootstrap.menu.Menu
19821 * @extends Roo.bootstrap.Component
19822 * Bootstrap Menu class - container for Menu
19823 * @cfg {String} html Text of the menu
19824 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19825 * @cfg {String} icon Font awesome icon
19826 * @cfg {String} pos Menu align to (top | bottom) default bottom
19830 * Create a new Menu
19831 * @param {Object} config The config object
19835 Roo.bootstrap.menu.Menu = function(config){
19836 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19840 * @event beforeshow
19841 * Fires before this menu is displayed
19842 * @param {Roo.bootstrap.menu.Menu} this
19846 * @event beforehide
19847 * Fires before this menu is hidden
19848 * @param {Roo.bootstrap.menu.Menu} this
19853 * Fires after this menu is displayed
19854 * @param {Roo.bootstrap.menu.Menu} this
19859 * Fires after this menu is hidden
19860 * @param {Roo.bootstrap.menu.Menu} this
19865 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19866 * @param {Roo.bootstrap.menu.Menu} this
19867 * @param {Roo.EventObject} e
19874 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19878 weight : 'default',
19883 getChildContainer : function() {
19884 if(this.isSubMenu){
19888 return this.el.select('ul.dropdown-menu', true).first();
19891 getAutoCreate : function()
19896 cls : 'roo-menu-text',
19904 cls : 'fa ' + this.icon
19915 cls : 'dropdown-button btn btn-' + this.weight,
19920 cls : 'dropdown-toggle btn btn-' + this.weight,
19930 cls : 'dropdown-menu'
19936 if(this.pos == 'top'){
19937 cfg.cls += ' dropup';
19940 if(this.isSubMenu){
19943 cls : 'dropdown-menu'
19950 onRender : function(ct, position)
19952 this.isSubMenu = ct.hasClass('dropdown-submenu');
19954 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19957 initEvents : function()
19959 if(this.isSubMenu){
19963 this.hidden = true;
19965 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19966 this.triggerEl.on('click', this.onTriggerPress, this);
19968 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19969 this.buttonEl.on('click', this.onClick, this);
19975 if(this.isSubMenu){
19979 return this.el.select('ul.dropdown-menu', true).first();
19982 onClick : function(e)
19984 this.fireEvent("click", this, e);
19987 onTriggerPress : function(e)
19989 if (this.isVisible()) {
19996 isVisible : function(){
19997 return !this.hidden;
20002 this.fireEvent("beforeshow", this);
20004 this.hidden = false;
20005 this.el.addClass('open');
20007 Roo.get(document).on("mouseup", this.onMouseUp, this);
20009 this.fireEvent("show", this);
20016 this.fireEvent("beforehide", this);
20018 this.hidden = true;
20019 this.el.removeClass('open');
20021 Roo.get(document).un("mouseup", this.onMouseUp);
20023 this.fireEvent("hide", this);
20026 onMouseUp : function()
20040 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20043 * @class Roo.bootstrap.menu.Item
20044 * @extends Roo.bootstrap.Component
20045 * Bootstrap MenuItem class
20046 * @cfg {Boolean} submenu (true | false) default false
20047 * @cfg {String} html text of the item
20048 * @cfg {String} href the link
20049 * @cfg {Boolean} disable (true | false) default false
20050 * @cfg {Boolean} preventDefault (true | false) default true
20051 * @cfg {String} icon Font awesome icon
20052 * @cfg {String} pos Submenu align to (left | right) default right
20056 * Create a new Item
20057 * @param {Object} config The config object
20061 Roo.bootstrap.menu.Item = function(config){
20062 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20066 * Fires when the mouse is hovering over this menu
20067 * @param {Roo.bootstrap.menu.Item} this
20068 * @param {Roo.EventObject} e
20073 * Fires when the mouse exits this menu
20074 * @param {Roo.bootstrap.menu.Item} this
20075 * @param {Roo.EventObject} e
20081 * The raw click event for the entire grid.
20082 * @param {Roo.EventObject} e
20088 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20093 preventDefault: true,
20098 getAutoCreate : function()
20103 cls : 'roo-menu-item-text',
20111 cls : 'fa ' + this.icon
20120 href : this.href || '#',
20127 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20131 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20133 if(this.pos == 'left'){
20134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20141 initEvents : function()
20143 this.el.on('mouseover', this.onMouseOver, this);
20144 this.el.on('mouseout', this.onMouseOut, this);
20146 this.el.select('a', true).first().on('click', this.onClick, this);
20150 onClick : function(e)
20152 if(this.preventDefault){
20153 e.preventDefault();
20156 this.fireEvent("click", this, e);
20159 onMouseOver : function(e)
20161 if(this.submenu && this.pos == 'left'){
20162 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20165 this.fireEvent("mouseover", this, e);
20168 onMouseOut : function(e)
20170 this.fireEvent("mouseout", this, e);
20182 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20185 * @class Roo.bootstrap.menu.Separator
20186 * @extends Roo.bootstrap.Component
20187 * Bootstrap Separator class
20190 * Create a new Separator
20191 * @param {Object} config The config object
20195 Roo.bootstrap.menu.Separator = function(config){
20196 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20199 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20201 getAutoCreate : function(){