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} selected The item selected
3220 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3227 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3238 getAutoCreate : function()
3240 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3247 if (['tabs','pills'].indexOf(this.type)!==-1) {
3248 cfg.cls += ' nav-' + this.type
3250 if (this.type!=='nav') {
3251 Roo.log('nav type must be nav/tabs/pills')
3253 cfg.cls += ' navbar-nav'
3256 if (this.parent().sidebar) {
3259 cls: 'dashboard-menu sidebar-menu'
3265 if (this.form === true) {
3271 if (this.align === 'right') {
3272 cfg.cls += ' navbar-right';
3274 cfg.cls += ' navbar-left';
3278 if (this.align === 'right') {
3279 cfg.cls += ' navbar-right';
3283 cfg.cls += ' navbar-inverse';
3291 * sets the active Navigation item
3292 * @param {Roo.bootstrap.NavItem} the new current navitem
3294 setActiveItem : function(item)
3297 Roo.each(this.navItems, function(v){
3302 v.setActive(false, true);
3309 item.setActive(true, true);
3310 this.fireEvent('changed', this, item, prev);
3315 * gets the active Navigation item
3316 * @return {Roo.bootstrap.NavItem} the current navitem
3318 getActive : function()
3322 Roo.each(this.navItems, function(v){
3333 indexOfNav : function()
3337 Roo.each(this.navItems, function(v,i){
3348 * adds a Navigation item
3349 * @param {Roo.bootstrap.NavItem} the navitem to add
3351 addItem : function(cfg)
3353 var cn = new Roo.bootstrap.NavItem(cfg);
3355 cn.parentId = this.id;
3356 cn.onRender(this.el, null);
3360 * register a Navigation item
3361 * @param {Roo.bootstrap.NavItem} the navitem to add
3363 register : function(item)
3365 this.navItems.push( item);
3366 item.navId = this.navId;
3371 getNavItem: function(tabId)
3374 Roo.each(this.navItems, function(e) {
3375 if (e.tabId == tabId) {
3385 setActiveNext : function()
3387 var i = this.indexOfNav(this.getActive());
3388 if (i > this.navItems.length) {
3391 this.setActiveItem(this.navItems[i+1]);
3393 setActivePrev : function()
3395 var i = this.indexOfNav(this.getActive());
3399 this.setActiveItem(this.navItems[i-1]);
3401 clearWasActive : function(except) {
3402 Roo.each(this.navItems, function(e) {
3403 if (e.tabId != except.tabId && e.was_active) {
3404 e.was_active = false;
3411 getWasActive : function ()
3414 Roo.each(this.navItems, function(e) {
3429 Roo.apply(Roo.bootstrap.NavGroup, {
3433 * register a Navigation Group
3434 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3436 register : function(navgrp)
3438 this.groups[navgrp.navId] = navgrp;
3442 * fetch a Navigation Group based on the navigation ID
3443 * @param {string} the navgroup to add
3444 * @returns {Roo.bootstrap.NavGroup} the navgroup
3446 get: function(navId) {
3447 if (typeof(this.groups[navId]) == 'undefined') {
3449 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3451 return this.groups[navId] ;
3466 * @class Roo.bootstrap.NavItem
3467 * @extends Roo.bootstrap.Component
3468 * Bootstrap Navbar.NavItem class
3469 * @cfg {String} href link to
3470 * @cfg {String} html content of button
3471 * @cfg {String} badge text inside badge
3472 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3473 * @cfg {String} glyphicon name of glyphicon
3474 * @cfg {String} icon name of font awesome icon
3475 * @cfg {Boolean} active Is item active
3476 * @cfg {Boolean} disabled Is item disabled
3478 * @cfg {Boolean} preventDefault (true | false) default false
3479 * @cfg {String} tabId the tab that this item activates.
3480 * @cfg {String} tagtype (a|span) render as a href or span?
3483 * Create a new Navbar Item
3484 * @param {Object} config The config object
3486 Roo.bootstrap.NavItem = function(config){
3487 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3492 * The raw click event for the entire grid.
3493 * @param {Roo.EventObject} e
3498 * Fires when the active item active state changes
3499 * @param {Roo.bootstrap.NavItem} this
3500 * @param {boolean} state the new state
3508 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3516 preventDefault : false,
3523 getAutoCreate : function(){
3531 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3533 if (this.disabled) {
3534 cfg.cls += ' disabled';
3537 if (this.href || this.html || this.glyphicon || this.icon) {
3541 href : this.href || "#",
3542 html: this.html || ''
3547 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3550 if(this.glyphicon) {
3551 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3556 cfg.cn[0].html += " <span class='caret'></span>";
3560 if (this.badge !== '') {
3562 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3570 initEvents: function() {
3571 // Roo.log('init events?');
3572 // Roo.log(this.el.dom);
3573 if (typeof (this.menu) != 'undefined') {
3574 this.menu.parentType = this.xtype;
3575 this.menu.triggerEl = this.el;
3576 this.addxtype(Roo.apply({}, this.menu));
3580 this.el.select('a',true).on('click', this.onClick, this);
3581 // at this point parent should be available..
3582 this.parent().register(this);
3585 onClick : function(e)
3588 if(this.preventDefault){
3591 if (this.disabled) {
3595 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3596 if (tg && tg.transition) {
3597 Roo.log("waiting for the transitionend");
3601 Roo.log("fire event clicked");
3602 if(this.fireEvent('click', this, e) === false){
3606 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3607 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3608 this.parent().setActiveItem(this);
3613 isActive: function () {
3616 setActive : function(state, fire, is_was_active)
3618 if (this.active && !state & this.navId) {
3619 this.was_active = true;
3620 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3622 nv.clearWasActive(this);
3626 this.active = state;
3629 this.el.removeClass('active');
3630 } else if (!this.el.hasClass('active')) {
3631 this.el.addClass('active');
3634 this.fireEvent('changed', this, state);
3637 // show a panel if it's registered and related..
3639 if (!this.navId || !this.tabId || !state || is_was_active) {
3643 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3647 var pan = tg.getPanelByName(this.tabId);
3651 // if we can not flip to new panel - go back to old nav highlight..
3652 if (false == tg.showPanel(pan)) {
3653 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3655 var onav = nv.getWasActive();
3657 onav.setActive(true, false, true);
3666 // this should not be here...
3667 setDisabled : function(state)
3669 this.disabled = state;
3671 this.el.removeClass('disabled');
3672 } else if (!this.el.hasClass('disabled')) {
3673 this.el.addClass('disabled');
3686 * <span> icon </span>
3687 * <span> text </span>
3688 * <span>badge </span>
3692 * @class Roo.bootstrap.NavSidebarItem
3693 * @extends Roo.bootstrap.NavItem
3694 * Bootstrap Navbar.NavSidebarItem class
3696 * Create a new Navbar Button
3697 * @param {Object} config The config object
3699 Roo.bootstrap.NavSidebarItem = function(config){
3700 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3705 * The raw click event for the entire grid.
3706 * @param {Roo.EventObject} e
3711 * Fires when the active item active state changes
3712 * @param {Roo.bootstrap.NavSidebarItem} this
3713 * @param {boolean} state the new state
3721 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3724 getAutoCreate : function(){
3729 href : this.href || '#',
3741 html : this.html || ''
3746 cfg.cls += ' active';
3750 if (this.glyphicon || this.icon) {
3751 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3752 a.cn.push({ tag : 'i', cls : c }) ;
3757 if (this.badge !== '') {
3758 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3762 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3763 a.cls += 'dropdown-toggle treeview' ;
3787 * @class Roo.bootstrap.Row
3788 * @extends Roo.bootstrap.Component
3789 * Bootstrap Row class (contains columns...)
3793 * @param {Object} config The config object
3796 Roo.bootstrap.Row = function(config){
3797 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3800 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3802 getAutoCreate : function(){
3821 * @class Roo.bootstrap.Element
3822 * @extends Roo.bootstrap.Component
3823 * Bootstrap Element class
3824 * @cfg {String} html contents of the element
3825 * @cfg {String} tag tag of the element
3826 * @cfg {String} cls class of the element
3829 * Create a new Element
3830 * @param {Object} config The config object
3833 Roo.bootstrap.Element = function(config){
3834 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3837 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3844 getAutoCreate : function(){
3869 * @class Roo.bootstrap.Pagination
3870 * @extends Roo.bootstrap.Component
3871 * Bootstrap Pagination class
3872 * @cfg {String} size xs | sm | md | lg
3873 * @cfg {Boolean} inverse false | true
3876 * Create a new Pagination
3877 * @param {Object} config The config object
3880 Roo.bootstrap.Pagination = function(config){
3881 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3884 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3890 getAutoCreate : function(){
3896 cfg.cls += ' inverse';
3902 cfg.cls += " " + this.cls;
3920 * @class Roo.bootstrap.PaginationItem
3921 * @extends Roo.bootstrap.Component
3922 * Bootstrap PaginationItem class
3923 * @cfg {String} html text
3924 * @cfg {String} href the link
3925 * @cfg {Boolean} preventDefault (true | false) default true
3926 * @cfg {Boolean} active (true | false) default false
3930 * Create a new PaginationItem
3931 * @param {Object} config The config object
3935 Roo.bootstrap.PaginationItem = function(config){
3936 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3941 * The raw click event for the entire grid.
3942 * @param {Roo.EventObject} e
3948 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3952 preventDefault: true,
3956 getAutoCreate : function(){
3962 href : this.href ? this.href : '#',
3963 html : this.html ? this.html : ''
3973 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3979 initEvents: function() {
3981 this.el.on('click', this.onClick, this);
3984 onClick : function(e)
3986 Roo.log('PaginationItem on click ');
3987 if(this.preventDefault){
3991 this.fireEvent('click', this, e);
4007 * @class Roo.bootstrap.Slider
4008 * @extends Roo.bootstrap.Component
4009 * Bootstrap Slider class
4012 * Create a new Slider
4013 * @param {Object} config The config object
4016 Roo.bootstrap.Slider = function(config){
4017 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4020 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4022 getAutoCreate : function(){
4026 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4030 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4042 * Ext JS Library 1.1.1
4043 * Copyright(c) 2006-2007, Ext JS, LLC.
4045 * Originally Released Under LGPL - original licence link has changed is not relivant.
4048 * <script type="text/javascript">
4053 * @class Roo.grid.ColumnModel
4054 * @extends Roo.util.Observable
4055 * This is the default implementation of a ColumnModel used by the Grid. It defines
4056 * the columns in the grid.
4059 var colModel = new Roo.grid.ColumnModel([
4060 {header: "Ticker", width: 60, sortable: true, locked: true},
4061 {header: "Company Name", width: 150, sortable: true},
4062 {header: "Market Cap.", width: 100, sortable: true},
4063 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4064 {header: "Employees", width: 100, sortable: true, resizable: false}
4069 * The config options listed for this class are options which may appear in each
4070 * individual column definition.
4071 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4073 * @param {Object} config An Array of column config objects. See this class's
4074 * config objects for details.
4076 Roo.grid.ColumnModel = function(config){
4078 * The config passed into the constructor
4080 this.config = config;
4083 // if no id, create one
4084 // if the column does not have a dataIndex mapping,
4085 // map it to the order it is in the config
4086 for(var i = 0, len = config.length; i < len; i++){
4088 if(typeof c.dataIndex == "undefined"){
4091 if(typeof c.renderer == "string"){
4092 c.renderer = Roo.util.Format[c.renderer];
4094 if(typeof c.id == "undefined"){
4097 if(c.editor && c.editor.xtype){
4098 c.editor = Roo.factory(c.editor, Roo.grid);
4100 if(c.editor && c.editor.isFormField){
4101 c.editor = new Roo.grid.GridEditor(c.editor);
4103 this.lookup[c.id] = c;
4107 * The width of columns which have no width specified (defaults to 100)
4110 this.defaultWidth = 100;
4113 * Default sortable of columns which have no sortable specified (defaults to false)
4116 this.defaultSortable = false;
4120 * @event widthchange
4121 * Fires when the width of a column changes.
4122 * @param {ColumnModel} this
4123 * @param {Number} columnIndex The column index
4124 * @param {Number} newWidth The new width
4126 "widthchange": true,
4128 * @event headerchange
4129 * Fires when the text of a header changes.
4130 * @param {ColumnModel} this
4131 * @param {Number} columnIndex The column index
4132 * @param {Number} newText The new header text
4134 "headerchange": true,
4136 * @event hiddenchange
4137 * Fires when a column is hidden or "unhidden".
4138 * @param {ColumnModel} this
4139 * @param {Number} columnIndex The column index
4140 * @param {Boolean} hidden true if hidden, false otherwise
4142 "hiddenchange": true,
4144 * @event columnmoved
4145 * Fires when a column is moved.
4146 * @param {ColumnModel} this
4147 * @param {Number} oldIndex
4148 * @param {Number} newIndex
4150 "columnmoved" : true,
4152 * @event columlockchange
4153 * Fires when a column's locked state is changed
4154 * @param {ColumnModel} this
4155 * @param {Number} colIndex
4156 * @param {Boolean} locked true if locked
4158 "columnlockchange" : true
4160 Roo.grid.ColumnModel.superclass.constructor.call(this);
4162 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4164 * @cfg {String} header The header text to display in the Grid view.
4167 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4168 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4169 * specified, the column's index is used as an index into the Record's data Array.
4172 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4173 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4176 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4177 * Defaults to the value of the {@link #defaultSortable} property.
4178 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4181 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4184 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4187 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4190 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4193 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4194 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4195 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4196 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4199 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4202 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4206 * Returns the id of the column at the specified index.
4207 * @param {Number} index The column index
4208 * @return {String} the id
4210 getColumnId : function(index){
4211 return this.config[index].id;
4215 * Returns the column for a specified id.
4216 * @param {String} id The column id
4217 * @return {Object} the column
4219 getColumnById : function(id){
4220 return this.lookup[id];
4225 * Returns the column for a specified dataIndex.
4226 * @param {String} dataIndex The column dataIndex
4227 * @return {Object|Boolean} the column or false if not found
4229 getColumnByDataIndex: function(dataIndex){
4230 var index = this.findColumnIndex(dataIndex);
4231 return index > -1 ? this.config[index] : false;
4235 * Returns the index for a specified column id.
4236 * @param {String} id The column id
4237 * @return {Number} the index, or -1 if not found
4239 getIndexById : function(id){
4240 for(var i = 0, len = this.config.length; i < len; i++){
4241 if(this.config[i].id == id){
4249 * Returns the index for a specified column dataIndex.
4250 * @param {String} dataIndex The column dataIndex
4251 * @return {Number} the index, or -1 if not found
4254 findColumnIndex : function(dataIndex){
4255 for(var i = 0, len = this.config.length; i < len; i++){
4256 if(this.config[i].dataIndex == dataIndex){
4264 moveColumn : function(oldIndex, newIndex){
4265 var c = this.config[oldIndex];
4266 this.config.splice(oldIndex, 1);
4267 this.config.splice(newIndex, 0, c);
4268 this.dataMap = null;
4269 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4272 isLocked : function(colIndex){
4273 return this.config[colIndex].locked === true;
4276 setLocked : function(colIndex, value, suppressEvent){
4277 if(this.isLocked(colIndex) == value){
4280 this.config[colIndex].locked = value;
4282 this.fireEvent("columnlockchange", this, colIndex, value);
4286 getTotalLockedWidth : function(){
4288 for(var i = 0; i < this.config.length; i++){
4289 if(this.isLocked(i) && !this.isHidden(i)){
4290 this.totalWidth += this.getColumnWidth(i);
4296 getLockedCount : function(){
4297 for(var i = 0, len = this.config.length; i < len; i++){
4298 if(!this.isLocked(i)){
4305 * Returns the number of columns.
4308 getColumnCount : function(visibleOnly){
4309 if(visibleOnly === true){
4311 for(var i = 0, len = this.config.length; i < len; i++){
4312 if(!this.isHidden(i)){
4318 return this.config.length;
4322 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4323 * @param {Function} fn
4324 * @param {Object} scope (optional)
4325 * @return {Array} result
4327 getColumnsBy : function(fn, scope){
4329 for(var i = 0, len = this.config.length; i < len; i++){
4330 var c = this.config[i];
4331 if(fn.call(scope||this, c, i) === true){
4339 * Returns true if the specified column is sortable.
4340 * @param {Number} col The column index
4343 isSortable : function(col){
4344 if(typeof this.config[col].sortable == "undefined"){
4345 return this.defaultSortable;
4347 return this.config[col].sortable;
4351 * Returns the rendering (formatting) function defined for the column.
4352 * @param {Number} col The column index.
4353 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4355 getRenderer : function(col){
4356 if(!this.config[col].renderer){
4357 return Roo.grid.ColumnModel.defaultRenderer;
4359 return this.config[col].renderer;
4363 * Sets the rendering (formatting) function for a column.
4364 * @param {Number} col The column index
4365 * @param {Function} fn The function to use to process the cell's raw data
4366 * to return HTML markup for the grid view. The render function is called with
4367 * the following parameters:<ul>
4368 * <li>Data value.</li>
4369 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4370 * <li>css A CSS style string to apply to the table cell.</li>
4371 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4372 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4373 * <li>Row index</li>
4374 * <li>Column index</li>
4375 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4377 setRenderer : function(col, fn){
4378 this.config[col].renderer = fn;
4382 * Returns the width for the specified column.
4383 * @param {Number} col The column index
4386 getColumnWidth : function(col){
4387 return this.config[col].width * 1 || this.defaultWidth;
4391 * Sets the width for a column.
4392 * @param {Number} col The column index
4393 * @param {Number} width The new width
4395 setColumnWidth : function(col, width, suppressEvent){
4396 this.config[col].width = width;
4397 this.totalWidth = null;
4399 this.fireEvent("widthchange", this, col, width);
4404 * Returns the total width of all columns.
4405 * @param {Boolean} includeHidden True to include hidden column widths
4408 getTotalWidth : function(includeHidden){
4409 if(!this.totalWidth){
4410 this.totalWidth = 0;
4411 for(var i = 0, len = this.config.length; i < len; i++){
4412 if(includeHidden || !this.isHidden(i)){
4413 this.totalWidth += this.getColumnWidth(i);
4417 return this.totalWidth;
4421 * Returns the header for the specified column.
4422 * @param {Number} col The column index
4425 getColumnHeader : function(col){
4426 return this.config[col].header;
4430 * Sets the header for a column.
4431 * @param {Number} col The column index
4432 * @param {String} header The new header
4434 setColumnHeader : function(col, header){
4435 this.config[col].header = header;
4436 this.fireEvent("headerchange", this, col, header);
4440 * Returns the tooltip for the specified column.
4441 * @param {Number} col The column index
4444 getColumnTooltip : function(col){
4445 return this.config[col].tooltip;
4448 * Sets the tooltip for a column.
4449 * @param {Number} col The column index
4450 * @param {String} tooltip The new tooltip
4452 setColumnTooltip : function(col, tooltip){
4453 this.config[col].tooltip = tooltip;
4457 * Returns the dataIndex for the specified column.
4458 * @param {Number} col The column index
4461 getDataIndex : function(col){
4462 return this.config[col].dataIndex;
4466 * Sets the dataIndex for a column.
4467 * @param {Number} col The column index
4468 * @param {Number} dataIndex The new dataIndex
4470 setDataIndex : function(col, dataIndex){
4471 this.config[col].dataIndex = dataIndex;
4477 * Returns true if the cell is editable.
4478 * @param {Number} colIndex The column index
4479 * @param {Number} rowIndex The row index
4482 isCellEditable : function(colIndex, rowIndex){
4483 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4487 * Returns the editor defined for the cell/column.
4488 * return false or null to disable editing.
4489 * @param {Number} colIndex The column index
4490 * @param {Number} rowIndex The row index
4493 getCellEditor : function(colIndex, rowIndex){
4494 return this.config[colIndex].editor;
4498 * Sets if a column is editable.
4499 * @param {Number} col The column index
4500 * @param {Boolean} editable True if the column is editable
4502 setEditable : function(col, editable){
4503 this.config[col].editable = editable;
4508 * Returns true if the column is hidden.
4509 * @param {Number} colIndex The column index
4512 isHidden : function(colIndex){
4513 return this.config[colIndex].hidden;
4518 * Returns true if the column width cannot be changed
4520 isFixed : function(colIndex){
4521 return this.config[colIndex].fixed;
4525 * Returns true if the column can be resized
4528 isResizable : function(colIndex){
4529 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4532 * Sets if a column is hidden.
4533 * @param {Number} colIndex The column index
4534 * @param {Boolean} hidden True if the column is hidden
4536 setHidden : function(colIndex, hidden){
4537 this.config[colIndex].hidden = hidden;
4538 this.totalWidth = null;
4539 this.fireEvent("hiddenchange", this, colIndex, hidden);
4543 * Sets the editor for a column.
4544 * @param {Number} col The column index
4545 * @param {Object} editor The editor object
4547 setEditor : function(col, editor){
4548 this.config[col].editor = editor;
4552 Roo.grid.ColumnModel.defaultRenderer = function(value){
4553 if(typeof value == "string" && value.length < 1){
4559 // Alias for backwards compatibility
4560 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4563 * Ext JS Library 1.1.1
4564 * Copyright(c) 2006-2007, Ext JS, LLC.
4566 * Originally Released Under LGPL - original licence link has changed is not relivant.
4569 * <script type="text/javascript">
4573 * @class Roo.LoadMask
4574 * A simple utility class for generically masking elements while loading data. If the element being masked has
4575 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4576 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4577 * element's UpdateManager load indicator and will be destroyed after the initial load.
4579 * Create a new LoadMask
4580 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4581 * @param {Object} config The config object
4583 Roo.LoadMask = function(el, config){
4584 this.el = Roo.get(el);
4585 Roo.apply(this, config);
4587 this.store.on('beforeload', this.onBeforeLoad, this);
4588 this.store.on('load', this.onLoad, this);
4589 this.store.on('loadexception', this.onLoadException, this);
4590 this.removeMask = false;
4592 var um = this.el.getUpdateManager();
4593 um.showLoadIndicator = false; // disable the default indicator
4594 um.on('beforeupdate', this.onBeforeLoad, this);
4595 um.on('update', this.onLoad, this);
4596 um.on('failure', this.onLoad, this);
4597 this.removeMask = true;
4601 Roo.LoadMask.prototype = {
4603 * @cfg {Boolean} removeMask
4604 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4605 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4609 * The text to display in a centered loading message box (defaults to 'Loading...')
4613 * @cfg {String} msgCls
4614 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4616 msgCls : 'x-mask-loading',
4619 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4625 * Disables the mask to prevent it from being displayed
4627 disable : function(){
4628 this.disabled = true;
4632 * Enables the mask so that it can be displayed
4634 enable : function(){
4635 this.disabled = false;
4638 onLoadException : function()
4642 if (typeof(arguments[3]) != 'undefined') {
4643 Roo.MessageBox.alert("Error loading",arguments[3]);
4647 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4648 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4657 this.el.unmask(this.removeMask);
4662 this.el.unmask(this.removeMask);
4666 onBeforeLoad : function(){
4668 this.el.mask(this.msg, this.msgCls);
4673 destroy : function(){
4675 this.store.un('beforeload', this.onBeforeLoad, this);
4676 this.store.un('load', this.onLoad, this);
4677 this.store.un('loadexception', this.onLoadException, this);
4679 var um = this.el.getUpdateManager();
4680 um.un('beforeupdate', this.onBeforeLoad, this);
4681 um.un('update', this.onLoad, this);
4682 um.un('failure', this.onLoad, this);
4693 * @class Roo.bootstrap.Table
4694 * @extends Roo.bootstrap.Component
4695 * Bootstrap Table class
4696 * @cfg {String} cls table class
4697 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4698 * @cfg {String} bgcolor Specifies the background color for a table
4699 * @cfg {Number} border Specifies whether the table cells should have borders or not
4700 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4701 * @cfg {Number} cellspacing Specifies the space between cells
4702 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4703 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4704 * @cfg {String} sortable Specifies that the table should be sortable
4705 * @cfg {String} summary Specifies a summary of the content of a table
4706 * @cfg {Number} width Specifies the width of a table
4707 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4709 * @cfg {boolean} striped Should the rows be alternative striped
4710 * @cfg {boolean} bordered Add borders to the table
4711 * @cfg {boolean} hover Add hover highlighting
4712 * @cfg {boolean} condensed Format condensed
4713 * @cfg {boolean} responsive Format condensed
4714 * @cfg {Boolean} loadMask (true|false) default false
4715 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4716 * @cfg {Boolean} thead (true|false) generate thead, default true
4717 * @cfg {Boolean} RowSelection (true|false) default false
4718 * @cfg {Boolean} CellSelection (true|false) default false
4720 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4724 * Create a new Table
4725 * @param {Object} config The config object
4728 Roo.bootstrap.Table = function(config){
4729 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4732 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4733 this.sm = this.selModel;
4734 this.sm.xmodule = this.xmodule || false;
4736 if (this.cm && typeof(this.cm.config) == 'undefined') {
4737 this.colModel = new Roo.grid.ColumnModel(this.cm);
4738 this.cm = this.colModel;
4739 this.cm.xmodule = this.xmodule || false;
4742 this.store= Roo.factory(this.store, Roo.data);
4743 this.ds = this.store;
4744 this.ds.xmodule = this.xmodule || false;
4747 if (this.footer && this.store) {
4748 this.footer.dataSource = this.ds;
4749 this.footer = Roo.factory(this.footer);
4756 * Fires when a cell is clicked
4757 * @param {Roo.bootstrap.Table} this
4758 * @param {Roo.Element} el
4759 * @param {Number} rowIndex
4760 * @param {Number} columnIndex
4761 * @param {Roo.EventObject} e
4765 * @event celldblclick
4766 * Fires when a cell is double clicked
4767 * @param {Roo.bootstrap.Table} this
4768 * @param {Roo.Element} el
4769 * @param {Number} rowIndex
4770 * @param {Number} columnIndex
4771 * @param {Roo.EventObject} e
4773 "celldblclick" : true,
4776 * Fires when a row is clicked
4777 * @param {Roo.bootstrap.Table} this
4778 * @param {Roo.Element} el
4779 * @param {Number} rowIndex
4780 * @param {Roo.EventObject} e
4784 * @event rowdblclick
4785 * Fires when a row is double clicked
4786 * @param {Roo.bootstrap.Table} this
4787 * @param {Roo.Element} el
4788 * @param {Number} rowIndex
4789 * @param {Roo.EventObject} e
4791 "rowdblclick" : true,
4794 * Fires when a mouseover occur
4795 * @param {Roo.bootstrap.Table} this
4796 * @param {Roo.Element} el
4797 * @param {Number} rowIndex
4798 * @param {Number} columnIndex
4799 * @param {Roo.EventObject} e
4804 * Fires when a mouseout occur
4805 * @param {Roo.bootstrap.Table} this
4806 * @param {Roo.Element} el
4807 * @param {Number} rowIndex
4808 * @param {Number} columnIndex
4809 * @param {Roo.EventObject} e
4814 * Fires when a row is rendered, so you can change add a style to it.
4815 * @param {Roo.bootstrap.Table} this
4816 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4823 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4847 RowSelection : false,
4848 CellSelection : false,
4851 // Roo.Element - the tbody
4854 getAutoCreate : function(){
4855 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4864 cfg.cls += ' table-striped';
4868 cfg.cls += ' table-hover';
4870 if (this.bordered) {
4871 cfg.cls += ' table-bordered';
4873 if (this.condensed) {
4874 cfg.cls += ' table-condensed';
4876 if (this.responsive) {
4877 cfg.cls += ' table-responsive';
4881 cfg.cls+= ' ' +this.cls;
4884 // this lot should be simplifed...
4887 cfg.align=this.align;
4890 cfg.bgcolor=this.bgcolor;
4893 cfg.border=this.border;
4895 if (this.cellpadding) {
4896 cfg.cellpadding=this.cellpadding;
4898 if (this.cellspacing) {
4899 cfg.cellspacing=this.cellspacing;
4902 cfg.frame=this.frame;
4905 cfg.rules=this.rules;
4907 if (this.sortable) {
4908 cfg.sortable=this.sortable;
4911 cfg.summary=this.summary;
4914 cfg.width=this.width;
4917 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4920 if(this.store || this.cm){
4922 cfg.cn.push(this.renderHeader());
4925 cfg.cn.push(this.renderBody());
4928 cfg.cn.push(this.renderFooter());
4931 cfg.cls+= ' TableGrid';
4934 return { cn : [ cfg ] };
4937 initEvents : function()
4939 if(!this.store || !this.cm){
4943 //Roo.log('initEvents with ds!!!!');
4945 this.mainBody = this.el.select('tbody', true).first();
4950 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4951 e.on('click', _this.sort, _this);
4954 this.el.on("click", this.onClick, this);
4955 this.el.on("dblclick", this.onDblClick, this);
4957 this.parent().el.setStyle('position', 'relative');
4959 this.footer.parentId = this.id;
4960 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4963 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4965 this.store.on('load', this.onLoad, this);
4966 this.store.on('beforeload', this.onBeforeLoad, this);
4967 this.store.on('update', this.onUpdate, this);
4971 onMouseover : function(e, el)
4973 var cell = Roo.get(el);
4979 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4980 cell = cell.findParent('td', false, true);
4983 var row = cell.findParent('tr', false, true);
4984 var cellIndex = cell.dom.cellIndex;
4985 var rowIndex = row.dom.rowIndex - 1; // start from 0
4987 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4991 onMouseout : function(e, el)
4993 var cell = Roo.get(el);
4999 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5000 cell = cell.findParent('td', false, true);
5003 var row = cell.findParent('tr', false, true);
5004 var cellIndex = cell.dom.cellIndex;
5005 var rowIndex = row.dom.rowIndex - 1; // start from 0
5007 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5011 onClick : function(e, el)
5013 var cell = Roo.get(el);
5015 if(!cell || (!this.CellSelection && !this.RowSelection)){
5020 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5021 cell = cell.findParent('td', false, true);
5024 var row = cell.findParent('tr', false, true);
5025 var cellIndex = cell.dom.cellIndex;
5026 var rowIndex = row.dom.rowIndex - 1;
5028 if(this.CellSelection){
5029 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5032 if(this.RowSelection){
5033 this.fireEvent('rowclick', this, row, rowIndex, e);
5039 onDblClick : function(e,el)
5041 var cell = Roo.get(el);
5043 if(!cell || (!this.CellSelection && !this.RowSelection)){
5047 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5048 cell = cell.findParent('td', false, true);
5051 var row = cell.findParent('tr', false, true);
5052 var cellIndex = cell.dom.cellIndex;
5053 var rowIndex = row.dom.rowIndex - 1;
5055 if(this.CellSelection){
5056 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5059 if(this.RowSelection){
5060 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5064 sort : function(e,el)
5066 var col = Roo.get(el)
5068 if(!col.hasClass('sortable')){
5072 var sort = col.attr('sort');
5075 if(col.hasClass('glyphicon-arrow-up')){
5079 this.store.sortInfo = {field : sort, direction : dir};
5082 Roo.log("calling footer first");
5083 this.footer.onClick('first');
5086 this.store.load({ params : { start : 0 } });
5090 renderHeader : function()
5099 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5101 var config = cm.config[i];
5106 html: cm.getColumnHeader(i)
5109 if(typeof(config.hidden) != 'undefined' && config.hidden){
5110 c.style += ' display:none;';
5113 if(typeof(config.dataIndex) != 'undefined'){
5114 c.sort = config.dataIndex;
5117 if(typeof(config.sortable) != 'undefined' && config.sortable){
5121 if(typeof(config.align) != 'undefined' && config.align.length){
5122 c.style += ' text-align:' + config.align + ';';
5125 if(typeof(config.width) != 'undefined'){
5126 c.style += ' width:' + config.width + 'px;';
5135 renderBody : function()
5145 colspan : this.cm.getColumnCount()
5155 renderFooter : function()
5165 colspan : this.cm.getColumnCount()
5179 Roo.log('ds onload');
5184 var ds = this.store;
5186 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5187 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5189 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5190 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5193 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5194 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5198 var tbody = this.mainBody;
5200 if(ds.getCount() > 0){
5201 ds.data.each(function(d,rowIndex){
5202 var row = this.renderRow(cm, ds, rowIndex);
5204 tbody.createChild(row);
5208 if(row.cellObjects.length){
5209 Roo.each(row.cellObjects, function(r){
5210 _this.renderCellObject(r);
5217 Roo.each(this.el.select('tbody td', true).elements, function(e){
5218 e.on('mouseover', _this.onMouseover, _this);
5221 Roo.each(this.el.select('tbody td', true).elements, function(e){
5222 e.on('mouseout', _this.onMouseout, _this);
5225 //if(this.loadMask){
5226 // this.maskEl.hide();
5231 onUpdate : function(ds,record)
5233 this.refreshRow(record);
5235 onRemove : function(ds, record, index, isUpdate){
5236 if(isUpdate !== true){
5237 this.fireEvent("beforerowremoved", this, index, record);
5239 var bt = this.mainBody.dom;
5241 bt.removeChild(bt.rows[index]);
5244 if(isUpdate !== true){
5245 //this.stripeRows(index);
5246 //this.syncRowHeights(index, index);
5248 this.fireEvent("rowremoved", this, index, record);
5253 refreshRow : function(record){
5254 var ds = this.store, index;
5255 if(typeof record == 'number'){
5257 record = ds.getAt(index);
5259 index = ds.indexOf(record);
5261 this.insertRow(ds, index, true);
5262 this.onRemove(ds, record, index+1, true);
5263 //this.syncRowHeights(index, index);
5265 this.fireEvent("rowupdated", this, index, record);
5268 insertRow : function(dm, rowIndex, isUpdate){
5271 this.fireEvent("beforerowsinserted", this, rowIndex);
5273 //var s = this.getScrollState();
5274 var row = this.renderRow(this.cm, this.store, rowIndex);
5275 // insert before rowIndex..
5276 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5280 if(row.cellObjects.length){
5281 Roo.each(row.cellObjects, function(r){
5282 _this.renderCellObject(r);
5287 this.fireEvent("rowsinserted", this, rowIndex);
5288 //this.syncRowHeights(firstRow, lastRow);
5289 //this.stripeRows(firstRow);
5296 getRowDom : function(rowIndex)
5298 // not sure if I need to check this.. but let's do it anyway..
5299 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5300 this.mainBody.dom.rows[rowIndex] : false
5302 // returns the object tree for a tr..
5305 renderRow : function(cm, ds, rowIndex) {
5307 var d = ds.getAt(rowIndex);
5314 var cellObjects = [];
5316 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5317 var config = cm.config[i];
5319 var renderer = cm.getRenderer(i);
5323 if(typeof(renderer) !== 'undefined'){
5324 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5326 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5327 // and are rendered into the cells after the row is rendered - using the id for the element.
5329 if(typeof(value) === 'object'){
5339 rowIndex : rowIndex,
5344 this.fireEvent('rowclass', this, rowcfg);
5348 cls : rowcfg.rowClass,
5350 html: (typeof(value) === 'object') ? '' : value
5357 if(typeof(config.hidden) != 'undefined' && config.hidden){
5358 td.style += ' display:none;';
5361 if(typeof(config.align) != 'undefined' && config.align.length){
5362 td.style += ' text-align:' + config.align + ';';
5365 if(typeof(config.width) != 'undefined'){
5366 td.style += ' width:' + config.width + 'px;';
5373 row.cellObjects = cellObjects;
5381 onBeforeLoad : function()
5383 //Roo.log('ds onBeforeLoad');
5387 //if(this.loadMask){
5388 // this.maskEl.show();
5394 this.el.select('tbody', true).first().dom.innerHTML = '';
5397 getSelectionModel : function(){
5399 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5401 return this.selModel;
5404 * Render the Roo.bootstrap object from renderder
5406 renderCellObject : function(r)
5410 var t = r.cfg.render(r.container);
5413 Roo.each(r.cfg.cn, function(c){
5415 container: t.getChildContainer(),
5418 _this.renderCellObject(child);
5435 * @class Roo.bootstrap.TableCell
5436 * @extends Roo.bootstrap.Component
5437 * Bootstrap TableCell class
5438 * @cfg {String} html cell contain text
5439 * @cfg {String} cls cell class
5440 * @cfg {String} tag cell tag (td|th) default td
5441 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5442 * @cfg {String} align Aligns the content in a cell
5443 * @cfg {String} axis Categorizes cells
5444 * @cfg {String} bgcolor Specifies the background color of a cell
5445 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5446 * @cfg {Number} colspan Specifies the number of columns a cell should span
5447 * @cfg {String} headers Specifies one or more header cells a cell is related to
5448 * @cfg {Number} height Sets the height of a cell
5449 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5450 * @cfg {Number} rowspan Sets the number of rows a cell should span
5451 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5452 * @cfg {String} valign Vertical aligns the content in a cell
5453 * @cfg {Number} width Specifies the width of a cell
5456 * Create a new TableCell
5457 * @param {Object} config The config object
5460 Roo.bootstrap.TableCell = function(config){
5461 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5464 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5484 getAutoCreate : function(){
5485 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5505 cfg.align=this.align
5511 cfg.bgcolor=this.bgcolor
5514 cfg.charoff=this.charoff
5517 cfg.colspan=this.colspan
5520 cfg.headers=this.headers
5523 cfg.height=this.height
5526 cfg.nowrap=this.nowrap
5529 cfg.rowspan=this.rowspan
5532 cfg.scope=this.scope
5535 cfg.valign=this.valign
5538 cfg.width=this.width
5557 * @class Roo.bootstrap.TableRow
5558 * @extends Roo.bootstrap.Component
5559 * Bootstrap TableRow class
5560 * @cfg {String} cls row class
5561 * @cfg {String} align Aligns the content in a table row
5562 * @cfg {String} bgcolor Specifies a background color for a table row
5563 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5564 * @cfg {String} valign Vertical aligns the content in a table row
5567 * Create a new TableRow
5568 * @param {Object} config The config object
5571 Roo.bootstrap.TableRow = function(config){
5572 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5575 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5583 getAutoCreate : function(){
5584 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5594 cfg.align = this.align;
5597 cfg.bgcolor = this.bgcolor;
5600 cfg.charoff = this.charoff;
5603 cfg.valign = this.valign;
5621 * @class Roo.bootstrap.TableBody
5622 * @extends Roo.bootstrap.Component
5623 * Bootstrap TableBody class
5624 * @cfg {String} cls element class
5625 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5626 * @cfg {String} align Aligns the content inside the element
5627 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5628 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5631 * Create a new TableBody
5632 * @param {Object} config The config object
5635 Roo.bootstrap.TableBody = function(config){
5636 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5639 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5647 getAutoCreate : function(){
5648 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5662 cfg.align = this.align;
5665 cfg.charoff = this.charoff;
5668 cfg.valign = this.valign;
5675 // initEvents : function()
5682 // this.store = Roo.factory(this.store, Roo.data);
5683 // this.store.on('load', this.onLoad, this);
5685 // this.store.load();
5689 // onLoad: function ()
5691 // this.fireEvent('load', this);
5701 * Ext JS Library 1.1.1
5702 * Copyright(c) 2006-2007, Ext JS, LLC.
5704 * Originally Released Under LGPL - original licence link has changed is not relivant.
5707 * <script type="text/javascript">
5710 // as we use this in bootstrap.
5711 Roo.namespace('Roo.form');
5713 * @class Roo.form.Action
5714 * Internal Class used to handle form actions
5716 * @param {Roo.form.BasicForm} el The form element or its id
5717 * @param {Object} config Configuration options
5722 // define the action interface
5723 Roo.form.Action = function(form, options){
5725 this.options = options || {};
5728 * Client Validation Failed
5731 Roo.form.Action.CLIENT_INVALID = 'client';
5733 * Server Validation Failed
5736 Roo.form.Action.SERVER_INVALID = 'server';
5738 * Connect to Server Failed
5741 Roo.form.Action.CONNECT_FAILURE = 'connect';
5743 * Reading Data from Server Failed
5746 Roo.form.Action.LOAD_FAILURE = 'load';
5748 Roo.form.Action.prototype = {
5750 failureType : undefined,
5751 response : undefined,
5755 run : function(options){
5760 success : function(response){
5765 handleResponse : function(response){
5769 // default connection failure
5770 failure : function(response){
5772 this.response = response;
5773 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5774 this.form.afterAction(this, false);
5777 processResponse : function(response){
5778 this.response = response;
5779 if(!response.responseText){
5782 this.result = this.handleResponse(response);
5786 // utility functions used internally
5787 getUrl : function(appendParams){
5788 var url = this.options.url || this.form.url || this.form.el.dom.action;
5790 var p = this.getParams();
5792 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5798 getMethod : function(){
5799 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5802 getParams : function(){
5803 var bp = this.form.baseParams;
5804 var p = this.options.params;
5806 if(typeof p == "object"){
5807 p = Roo.urlEncode(Roo.applyIf(p, bp));
5808 }else if(typeof p == 'string' && bp){
5809 p += '&' + Roo.urlEncode(bp);
5812 p = Roo.urlEncode(bp);
5817 createCallback : function(){
5819 success: this.success,
5820 failure: this.failure,
5822 timeout: (this.form.timeout*1000),
5823 upload: this.form.fileUpload ? this.success : undefined
5828 Roo.form.Action.Submit = function(form, options){
5829 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5832 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5835 haveProgress : false,
5836 uploadComplete : false,
5838 // uploadProgress indicator.
5839 uploadProgress : function()
5841 if (!this.form.progressUrl) {
5845 if (!this.haveProgress) {
5846 Roo.MessageBox.progress("Uploading", "Uploading");
5848 if (this.uploadComplete) {
5849 Roo.MessageBox.hide();
5853 this.haveProgress = true;
5855 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5857 var c = new Roo.data.Connection();
5859 url : this.form.progressUrl,
5864 success : function(req){
5865 //console.log(data);
5869 rdata = Roo.decode(req.responseText)
5871 Roo.log("Invalid data from server..");
5875 if (!rdata || !rdata.success) {
5877 Roo.MessageBox.alert(Roo.encode(rdata));
5880 var data = rdata.data;
5882 if (this.uploadComplete) {
5883 Roo.MessageBox.hide();
5888 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5889 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5892 this.uploadProgress.defer(2000,this);
5895 failure: function(data) {
5896 Roo.log('progress url failed ');
5907 // run get Values on the form, so it syncs any secondary forms.
5908 this.form.getValues();
5910 var o = this.options;
5911 var method = this.getMethod();
5912 var isPost = method == 'POST';
5913 if(o.clientValidation === false || this.form.isValid()){
5915 if (this.form.progressUrl) {
5916 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5917 (new Date() * 1) + '' + Math.random());
5922 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5923 form:this.form.el.dom,
5924 url:this.getUrl(!isPost),
5926 params:isPost ? this.getParams() : null,
5927 isUpload: this.form.fileUpload
5930 this.uploadProgress();
5932 }else if (o.clientValidation !== false){ // client validation failed
5933 this.failureType = Roo.form.Action.CLIENT_INVALID;
5934 this.form.afterAction(this, false);
5938 success : function(response)
5940 this.uploadComplete= true;
5941 if (this.haveProgress) {
5942 Roo.MessageBox.hide();
5946 var result = this.processResponse(response);
5947 if(result === true || result.success){
5948 this.form.afterAction(this, true);
5952 this.form.markInvalid(result.errors);
5953 this.failureType = Roo.form.Action.SERVER_INVALID;
5955 this.form.afterAction(this, false);
5957 failure : function(response)
5959 this.uploadComplete= true;
5960 if (this.haveProgress) {
5961 Roo.MessageBox.hide();
5964 this.response = response;
5965 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5966 this.form.afterAction(this, false);
5969 handleResponse : function(response){
5970 if(this.form.errorReader){
5971 var rs = this.form.errorReader.read(response);
5974 for(var i = 0, len = rs.records.length; i < len; i++) {
5975 var r = rs.records[i];
5979 if(errors.length < 1){
5983 success : rs.success,
5989 ret = Roo.decode(response.responseText);
5993 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6003 Roo.form.Action.Load = function(form, options){
6004 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6005 this.reader = this.form.reader;
6008 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6013 Roo.Ajax.request(Roo.apply(
6014 this.createCallback(), {
6015 method:this.getMethod(),
6016 url:this.getUrl(false),
6017 params:this.getParams()
6021 success : function(response){
6023 var result = this.processResponse(response);
6024 if(result === true || !result.success || !result.data){
6025 this.failureType = Roo.form.Action.LOAD_FAILURE;
6026 this.form.afterAction(this, false);
6029 this.form.clearInvalid();
6030 this.form.setValues(result.data);
6031 this.form.afterAction(this, true);
6034 handleResponse : function(response){
6035 if(this.form.reader){
6036 var rs = this.form.reader.read(response);
6037 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6039 success : rs.success,
6043 return Roo.decode(response.responseText);
6047 Roo.form.Action.ACTION_TYPES = {
6048 'load' : Roo.form.Action.Load,
6049 'submit' : Roo.form.Action.Submit
6058 * @class Roo.bootstrap.Form
6059 * @extends Roo.bootstrap.Component
6060 * Bootstrap Form class
6061 * @cfg {String} method GET | POST (default POST)
6062 * @cfg {String} labelAlign top | left (default top)
6063 * @cfg {String} align left | right - for navbars
6068 * @param {Object} config The config object
6072 Roo.bootstrap.Form = function(config){
6073 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6076 * @event clientvalidation
6077 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6078 * @param {Form} this
6079 * @param {Boolean} valid true if the form has passed client-side validation
6081 clientvalidation: true,
6083 * @event beforeaction
6084 * Fires before any action is performed. Return false to cancel the action.
6085 * @param {Form} this
6086 * @param {Action} action The action to be performed
6090 * @event actionfailed
6091 * Fires when an action fails.
6092 * @param {Form} this
6093 * @param {Action} action The action that failed
6095 actionfailed : true,
6097 * @event actioncomplete
6098 * Fires when an action is completed.
6099 * @param {Form} this
6100 * @param {Action} action The action that completed
6102 actioncomplete : true
6107 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6110 * @cfg {String} method
6111 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6116 * The URL to use for form actions if one isn't supplied in the action options.
6119 * @cfg {Boolean} fileUpload
6120 * Set to true if this form is a file upload.
6124 * @cfg {Object} baseParams
6125 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6129 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6133 * @cfg {Sting} align (left|right) for navbar forms
6138 activeAction : null,
6141 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6142 * element by passing it or its id or mask the form itself by passing in true.
6145 waitMsgTarget : false,
6150 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6151 * element by passing it or its id or mask the form itself by passing in true.
6155 getAutoCreate : function(){
6159 method : this.method || 'POST',
6160 id : this.id || Roo.id(),
6163 if (this.parent().xtype.match(/^Nav/)) {
6164 cfg.cls = 'navbar-form navbar-' + this.align;
6168 if (this.labelAlign == 'left' ) {
6169 cfg.cls += ' form-horizontal';
6175 initEvents : function()
6177 this.el.on('submit', this.onSubmit, this);
6178 // this was added as random key presses on the form where triggering form submit.
6179 this.el.on('keypress', function(e) {
6180 if (e.getCharCode() != 13) {
6183 // we might need to allow it for textareas.. and some other items.
6184 // check e.getTarget().
6186 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6190 Roo.log("keypress blocked");
6198 onSubmit : function(e){
6203 * Returns true if client-side validation on the form is successful.
6206 isValid : function(){
6207 var items = this.getItems();
6209 items.each(function(f){
6218 * Returns true if any fields in this form have changed since their original load.
6221 isDirty : function(){
6223 var items = this.getItems();
6224 items.each(function(f){
6234 * Performs a predefined action (submit or load) or custom actions you define on this form.
6235 * @param {String} actionName The name of the action type
6236 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6237 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6238 * accept other config options):
6240 Property Type Description
6241 ---------------- --------------- ----------------------------------------------------------------------------------
6242 url String The url for the action (defaults to the form's url)
6243 method String The form method to use (defaults to the form's method, or POST if not defined)
6244 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6245 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6246 validate the form on the client (defaults to false)
6248 * @return {BasicForm} this
6250 doAction : function(action, options){
6251 if(typeof action == 'string'){
6252 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6254 if(this.fireEvent('beforeaction', this, action) !== false){
6255 this.beforeAction(action);
6256 action.run.defer(100, action);
6262 beforeAction : function(action){
6263 var o = action.options;
6265 // not really supported yet.. ??
6267 //if(this.waitMsgTarget === true){
6268 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6269 //}else if(this.waitMsgTarget){
6270 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6271 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6273 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6279 afterAction : function(action, success){
6280 this.activeAction = null;
6281 var o = action.options;
6283 //if(this.waitMsgTarget === true){
6285 //}else if(this.waitMsgTarget){
6286 // this.waitMsgTarget.unmask();
6288 // Roo.MessageBox.updateProgress(1);
6289 // Roo.MessageBox.hide();
6296 Roo.callback(o.success, o.scope, [this, action]);
6297 this.fireEvent('actioncomplete', this, action);
6301 // failure condition..
6302 // we have a scenario where updates need confirming.
6303 // eg. if a locking scenario exists..
6304 // we look for { errors : { needs_confirm : true }} in the response.
6306 (typeof(action.result) != 'undefined') &&
6307 (typeof(action.result.errors) != 'undefined') &&
6308 (typeof(action.result.errors.needs_confirm) != 'undefined')
6311 Roo.log("not supported yet");
6314 Roo.MessageBox.confirm(
6315 "Change requires confirmation",
6316 action.result.errorMsg,
6321 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6331 Roo.callback(o.failure, o.scope, [this, action]);
6332 // show an error message if no failed handler is set..
6333 if (!this.hasListener('actionfailed')) {
6334 Roo.log("need to add dialog support");
6336 Roo.MessageBox.alert("Error",
6337 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6338 action.result.errorMsg :
6339 "Saving Failed, please check your entries or try again"
6344 this.fireEvent('actionfailed', this, action);
6349 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6350 * @param {String} id The value to search for
6353 findField : function(id){
6354 var items = this.getItems();
6355 var field = items.get(id);
6357 items.each(function(f){
6358 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6365 return field || null;
6368 * Mark fields in this form invalid in bulk.
6369 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6370 * @return {BasicForm} this
6372 markInvalid : function(errors){
6373 if(errors instanceof Array){
6374 for(var i = 0, len = errors.length; i < len; i++){
6375 var fieldError = errors[i];
6376 var f = this.findField(fieldError.id);
6378 f.markInvalid(fieldError.msg);
6384 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6385 field.markInvalid(errors[id]);
6389 //Roo.each(this.childForms || [], function (f) {
6390 // f.markInvalid(errors);
6397 * Set values for fields in this form in bulk.
6398 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6399 * @return {BasicForm} this
6401 setValues : function(values){
6402 if(values instanceof Array){ // array of objects
6403 for(var i = 0, len = values.length; i < len; i++){
6405 var f = this.findField(v.id);
6407 f.setValue(v.value);
6408 if(this.trackResetOnLoad){
6409 f.originalValue = f.getValue();
6413 }else{ // object hash
6416 if(typeof values[id] != 'function' && (field = this.findField(id))){
6418 if (field.setFromData &&
6420 field.displayField &&
6421 // combos' with local stores can
6422 // be queried via setValue()
6423 // to set their value..
6424 (field.store && !field.store.isLocal)
6428 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6429 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6430 field.setFromData(sd);
6433 field.setValue(values[id]);
6437 if(this.trackResetOnLoad){
6438 field.originalValue = field.getValue();
6444 //Roo.each(this.childForms || [], function (f) {
6445 // f.setValues(values);
6452 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6453 * they are returned as an array.
6454 * @param {Boolean} asString
6457 getValues : function(asString){
6458 //if (this.childForms) {
6459 // copy values from the child forms
6460 // Roo.each(this.childForms, function (f) {
6461 // this.setValues(f.getValues());
6467 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6468 if(asString === true){
6471 return Roo.urlDecode(fs);
6475 * Returns the fields in this form as an object with key/value pairs.
6476 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6479 getFieldValues : function(with_hidden)
6481 var items = this.getItems();
6483 items.each(function(f){
6487 var v = f.getValue();
6488 if (f.inputType =='radio') {
6489 if (typeof(ret[f.getName()]) == 'undefined') {
6490 ret[f.getName()] = ''; // empty..
6493 if (!f.el.dom.checked) {
6501 // not sure if this supported any more..
6502 if ((typeof(v) == 'object') && f.getRawValue) {
6503 v = f.getRawValue() ; // dates..
6505 // combo boxes where name != hiddenName...
6506 if (f.name != f.getName()) {
6507 ret[f.name] = f.getRawValue();
6509 ret[f.getName()] = v;
6516 * Clears all invalid messages in this form.
6517 * @return {BasicForm} this
6519 clearInvalid : function(){
6520 var items = this.getItems();
6522 items.each(function(f){
6533 * @return {BasicForm} this
6536 var items = this.getItems();
6537 items.each(function(f){
6541 Roo.each(this.childForms || [], function (f) {
6548 getItems : function()
6550 var r=new Roo.util.MixedCollection(false, function(o){
6551 return o.id || (o.id = Roo.id());
6553 var iter = function(el) {
6560 Roo.each(el.items,function(e) {
6579 * Ext JS Library 1.1.1
6580 * Copyright(c) 2006-2007, Ext JS, LLC.
6582 * Originally Released Under LGPL - original licence link has changed is not relivant.
6585 * <script type="text/javascript">
6588 * @class Roo.form.VTypes
6589 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6592 Roo.form.VTypes = function(){
6593 // closure these in so they are only created once.
6594 var alpha = /^[a-zA-Z_]+$/;
6595 var alphanum = /^[a-zA-Z0-9_]+$/;
6596 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6597 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6599 // All these messages and functions are configurable
6602 * The function used to validate email addresses
6603 * @param {String} value The email address
6605 'email' : function(v){
6606 return email.test(v);
6609 * The error text to display when the email validation function returns false
6612 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6614 * The keystroke filter mask to be applied on email input
6617 'emailMask' : /[a-z0-9_\.\-@]/i,
6620 * The function used to validate URLs
6621 * @param {String} value The URL
6623 'url' : function(v){
6627 * The error text to display when the url validation function returns false
6630 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6633 * The function used to validate alpha values
6634 * @param {String} value The value
6636 'alpha' : function(v){
6637 return alpha.test(v);
6640 * The error text to display when the alpha validation function returns false
6643 'alphaText' : 'This field should only contain letters and _',
6645 * The keystroke filter mask to be applied on alpha input
6648 'alphaMask' : /[a-z_]/i,
6651 * The function used to validate alphanumeric values
6652 * @param {String} value The value
6654 'alphanum' : function(v){
6655 return alphanum.test(v);
6658 * The error text to display when the alphanumeric validation function returns false
6661 'alphanumText' : 'This field should only contain letters, numbers and _',
6663 * The keystroke filter mask to be applied on alphanumeric input
6666 'alphanumMask' : /[a-z0-9_]/i
6676 * @class Roo.bootstrap.Input
6677 * @extends Roo.bootstrap.Component
6678 * Bootstrap Input class
6679 * @cfg {Boolean} disabled is it disabled
6680 * @cfg {String} fieldLabel - the label associated
6681 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6682 * @cfg {String} name name of the input
6683 * @cfg {string} fieldLabel - the label associated
6684 * @cfg {string} inputType - input / file submit ...
6685 * @cfg {string} placeholder - placeholder to put in text.
6686 * @cfg {string} before - input group add on before
6687 * @cfg {string} after - input group add on after
6688 * @cfg {string} size - (lg|sm) or leave empty..
6689 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6690 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6691 * @cfg {Number} md colspan out of 12 for computer-sized screens
6692 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6693 * @cfg {string} value default value of the input
6694 * @cfg {Number} labelWidth set the width of label (0-12)
6695 * @cfg {String} labelAlign (top|left)
6696 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6697 * @cfg {String} align (left|center|right) Default left
6701 * Create a new Input
6702 * @param {Object} config The config object
6705 Roo.bootstrap.Input = function(config){
6706 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6711 * Fires when this field receives input focus.
6712 * @param {Roo.form.Field} this
6717 * Fires when this field loses input focus.
6718 * @param {Roo.form.Field} this
6723 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6724 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6725 * @param {Roo.form.Field} this
6726 * @param {Roo.EventObject} e The event object
6731 * Fires just before the field blurs if the field value has changed.
6732 * @param {Roo.form.Field} this
6733 * @param {Mixed} newValue The new value
6734 * @param {Mixed} oldValue The original value
6739 * Fires after the field has been marked as invalid.
6740 * @param {Roo.form.Field} this
6741 * @param {String} msg The validation message
6746 * Fires after the field has been validated with no errors.
6747 * @param {Roo.form.Field} this
6752 * Fires after the key up
6753 * @param {Roo.form.Field} this
6754 * @param {Roo.EventObject} e The event Object
6760 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6762 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6763 automatic validation (defaults to "keyup").
6765 validationEvent : "keyup",
6767 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6769 validateOnBlur : true,
6771 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6773 validationDelay : 250,
6775 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6777 focusClass : "x-form-focus", // not needed???
6781 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6783 invalidClass : "has-error",
6786 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6788 selectOnFocus : false,
6791 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6795 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6800 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6802 disableKeyFilter : false,
6805 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6809 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6813 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6815 blankText : "This field is required",
6818 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6822 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6824 maxLength : Number.MAX_VALUE,
6826 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6828 minLengthText : "The minimum length for this field is {0}",
6830 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6832 maxLengthText : "The maximum length for this field is {0}",
6836 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6837 * If available, this function will be called only after the basic validators all return true, and will be passed the
6838 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6842 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6843 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6844 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6848 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6871 formatedValue : false,
6873 parentLabelAlign : function()
6876 while (parent.parent()) {
6877 parent = parent.parent();
6878 if (typeof(parent.labelAlign) !='undefined') {
6879 return parent.labelAlign;
6886 getAutoCreate : function(){
6888 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6894 if(this.inputType != 'hidden'){
6895 cfg.cls = 'form-group' //input-group
6901 type : this.inputType,
6903 cls : 'form-control',
6904 placeholder : this.placeholder || ''
6909 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6912 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6913 input.maxLength = this.maxLength;
6916 if (this.disabled) {
6917 input.disabled=true;
6920 if (this.readOnly) {
6921 input.readonly=true;
6925 input.name = this.name;
6928 input.cls += ' input-' + this.size;
6931 ['xs','sm','md','lg'].map(function(size){
6932 if (settings[size]) {
6933 cfg.cls += ' col-' + size + '-' + settings[size];
6937 var inputblock = input;
6939 if (this.before || this.after) {
6942 cls : 'input-group',
6945 if (this.before && typeof(this.before) == 'string') {
6947 inputblock.cn.push({
6949 cls : 'roo-input-before input-group-addon',
6953 if (this.before && typeof(this.before) == 'object') {
6954 this.before = Roo.factory(this.before);
6955 Roo.log(this.before);
6956 inputblock.cn.push({
6958 cls : 'roo-input-before input-group-' +
6959 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6963 inputblock.cn.push(input);
6965 if (this.after && typeof(this.after) == 'string') {
6966 inputblock.cn.push({
6968 cls : 'roo-input-after input-group-addon',
6972 if (this.after && typeof(this.after) == 'object') {
6973 this.after = Roo.factory(this.after);
6974 Roo.log(this.after);
6975 inputblock.cn.push({
6977 cls : 'roo-input-after input-group-' +
6978 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6983 if (align ==='left' && this.fieldLabel.length) {
6984 Roo.log("left and has label");
6990 cls : 'control-label col-sm-' + this.labelWidth,
6991 html : this.fieldLabel
6995 cls : "col-sm-" + (12 - this.labelWidth),
7002 } else if ( this.fieldLabel.length) {
7008 //cls : 'input-group-addon',
7009 html : this.fieldLabel
7019 Roo.log(" no label && no align");
7028 Roo.log('input-parentType: ' + this.parentType);
7030 if (this.parentType === 'Navbar' && this.parent().bar) {
7031 cfg.cls += ' navbar-form';
7039 * return the real input element.
7041 inputEl: function ()
7043 return this.el.select('input.form-control',true).first();
7045 setDisabled : function(v)
7047 var i = this.inputEl().dom;
7049 i.removeAttribute('disabled');
7053 i.setAttribute('disabled','true');
7055 initEvents : function()
7058 this.inputEl().on("keydown" , this.fireKey, this);
7059 this.inputEl().on("focus", this.onFocus, this);
7060 this.inputEl().on("blur", this.onBlur, this);
7062 this.inputEl().relayEvent('keyup', this);
7064 // reference to original value for reset
7065 this.originalValue = this.getValue();
7066 //Roo.form.TextField.superclass.initEvents.call(this);
7067 if(this.validationEvent == 'keyup'){
7068 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7069 this.inputEl().on('keyup', this.filterValidation, this);
7071 else if(this.validationEvent !== false){
7072 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7075 if(this.selectOnFocus){
7076 this.on("focus", this.preFocus, this);
7079 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7080 this.inputEl().on("keypress", this.filterKeys, this);
7083 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7084 this.el.on("click", this.autoSize, this);
7087 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7088 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7091 if (typeof(this.before) == 'object') {
7092 this.before.render(this.el.select('.roo-input-before',true).first());
7094 if (typeof(this.after) == 'object') {
7095 this.after.render(this.el.select('.roo-input-after',true).first());
7100 filterValidation : function(e){
7101 if(!e.isNavKeyPress()){
7102 this.validationTask.delay(this.validationDelay);
7106 * Validates the field value
7107 * @return {Boolean} True if the value is valid, else false
7109 validate : function(){
7110 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7111 if(this.disabled || this.validateValue(this.getRawValue())){
7112 this.clearInvalid();
7120 * Validates a value according to the field's validation rules and marks the field as invalid
7121 * if the validation fails
7122 * @param {Mixed} value The value to validate
7123 * @return {Boolean} True if the value is valid, else false
7125 validateValue : function(value){
7126 if(value.length < 1) { // if it's blank
7127 if(this.allowBlank){
7128 this.clearInvalid();
7131 this.markInvalid(this.blankText);
7135 if(value.length < this.minLength){
7136 this.markInvalid(String.format(this.minLengthText, this.minLength));
7139 if(value.length > this.maxLength){
7140 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7144 var vt = Roo.form.VTypes;
7145 if(!vt[this.vtype](value, this)){
7146 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7150 if(typeof this.validator == "function"){
7151 var msg = this.validator(value);
7153 this.markInvalid(msg);
7157 if(this.regex && !this.regex.test(value)){
7158 this.markInvalid(this.regexText);
7167 fireKey : function(e){
7168 //Roo.log('field ' + e.getKey());
7169 if(e.isNavKeyPress()){
7170 this.fireEvent("specialkey", this, e);
7173 focus : function (selectText){
7175 this.inputEl().focus();
7176 if(selectText === true){
7177 this.inputEl().dom.select();
7183 onFocus : function(){
7184 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7185 // this.el.addClass(this.focusClass);
7188 this.hasFocus = true;
7189 this.startValue = this.getValue();
7190 this.fireEvent("focus", this);
7194 beforeBlur : Roo.emptyFn,
7198 onBlur : function(){
7200 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7201 //this.el.removeClass(this.focusClass);
7203 this.hasFocus = false;
7204 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7207 var v = this.getValue();
7208 if(String(v) !== String(this.startValue)){
7209 this.fireEvent('change', this, v, this.startValue);
7211 this.fireEvent("blur", this);
7215 * Resets the current field value to the originally loaded value and clears any validation messages
7218 this.setValue(this.originalValue);
7219 this.clearInvalid();
7222 * Returns the name of the field
7223 * @return {Mixed} name The name field
7225 getName: function(){
7229 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7230 * @return {Mixed} value The field value
7232 getValue : function(){
7234 var v = this.inputEl().getValue();
7239 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7240 * @return {Mixed} value The field value
7242 getRawValue : function(){
7243 var v = this.inputEl().getValue();
7249 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7250 * @param {Mixed} value The value to set
7252 setRawValue : function(v){
7253 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7256 selectText : function(start, end){
7257 var v = this.getRawValue();
7259 start = start === undefined ? 0 : start;
7260 end = end === undefined ? v.length : end;
7261 var d = this.inputEl().dom;
7262 if(d.setSelectionRange){
7263 d.setSelectionRange(start, end);
7264 }else if(d.createTextRange){
7265 var range = d.createTextRange();
7266 range.moveStart("character", start);
7267 range.moveEnd("character", v.length-end);
7274 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7275 * @param {Mixed} value The value to set
7277 setValue : function(v){
7280 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7286 processValue : function(value){
7287 if(this.stripCharsRe){
7288 var newValue = value.replace(this.stripCharsRe, '');
7289 if(newValue !== value){
7290 this.setRawValue(newValue);
7297 preFocus : function(){
7299 if(this.selectOnFocus){
7300 this.inputEl().dom.select();
7303 filterKeys : function(e){
7305 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7308 var c = e.getCharCode(), cc = String.fromCharCode(c);
7309 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7312 if(!this.maskRe.test(cc)){
7317 * Clear any invalid styles/messages for this field
7319 clearInvalid : function(){
7321 if(!this.el || this.preventMark){ // not rendered
7324 this.el.removeClass(this.invalidClass);
7326 switch(this.msgTarget){
7328 this.el.dom.qtip = '';
7331 this.el.dom.title = '';
7335 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7340 this.errorIcon.dom.qtip = '';
7341 this.errorIcon.hide();
7342 this.un('resize', this.alignErrorIcon, this);
7346 var t = Roo.getDom(this.msgTarget);
7348 t.style.display = 'none';
7352 this.fireEvent('valid', this);
7355 * Mark this field as invalid
7356 * @param {String} msg The validation message
7358 markInvalid : function(msg){
7359 if(!this.el || this.preventMark){ // not rendered
7362 this.el.addClass(this.invalidClass);
7364 msg = msg || this.invalidText;
7365 switch(this.msgTarget){
7367 this.el.dom.qtip = msg;
7368 this.el.dom.qclass = 'x-form-invalid-tip';
7369 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7370 Roo.QuickTips.enable();
7374 this.el.dom.title = msg;
7378 var elp = this.el.findParent('.x-form-element', 5, true);
7379 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7380 this.errorEl.setWidth(elp.getWidth(true)-20);
7382 this.errorEl.update(msg);
7383 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7386 if(!this.errorIcon){
7387 var elp = this.el.findParent('.x-form-element', 5, true);
7388 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7390 this.alignErrorIcon();
7391 this.errorIcon.dom.qtip = msg;
7392 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7393 this.errorIcon.show();
7394 this.on('resize', this.alignErrorIcon, this);
7397 var t = Roo.getDom(this.msgTarget);
7399 t.style.display = this.msgDisplay;
7403 this.fireEvent('invalid', this, msg);
7406 SafariOnKeyDown : function(event)
7408 // this is a workaround for a password hang bug on chrome/ webkit.
7410 var isSelectAll = false;
7412 if(this.inputEl().dom.selectionEnd > 0){
7413 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7415 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7416 event.preventDefault();
7421 if(isSelectAll){ // backspace and delete key
7423 event.preventDefault();
7424 // this is very hacky as keydown always get's upper case.
7426 var cc = String.fromCharCode(event.getCharCode());
7427 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7431 adjustWidth : function(tag, w){
7432 tag = tag.toLowerCase();
7433 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7434 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7438 if(tag == 'textarea'){
7441 }else if(Roo.isOpera){
7445 if(tag == 'textarea'){
7464 * @class Roo.bootstrap.TextArea
7465 * @extends Roo.bootstrap.Input
7466 * Bootstrap TextArea class
7467 * @cfg {Number} cols Specifies the visible width of a text area
7468 * @cfg {Number} rows Specifies the visible number of lines in a text area
7469 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7470 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7471 * @cfg {string} html text
7474 * Create a new TextArea
7475 * @param {Object} config The config object
7478 Roo.bootstrap.TextArea = function(config){
7479 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7483 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7493 getAutoCreate : function(){
7495 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7506 value : this.value || '',
7507 html: this.html || '',
7508 cls : 'form-control',
7509 placeholder : this.placeholder || ''
7513 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7514 input.maxLength = this.maxLength;
7518 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7522 input.cols = this.cols;
7525 if (this.readOnly) {
7526 input.readonly = true;
7530 input.name = this.name;
7534 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7538 ['xs','sm','md','lg'].map(function(size){
7539 if (settings[size]) {
7540 cfg.cls += ' col-' + size + '-' + settings[size];
7544 var inputblock = input;
7546 if (this.before || this.after) {
7549 cls : 'input-group',
7553 inputblock.cn.push({
7555 cls : 'input-group-addon',
7559 inputblock.cn.push(input);
7561 inputblock.cn.push({
7563 cls : 'input-group-addon',
7570 if (align ==='left' && this.fieldLabel.length) {
7571 Roo.log("left and has label");
7577 cls : 'control-label col-sm-' + this.labelWidth,
7578 html : this.fieldLabel
7582 cls : "col-sm-" + (12 - this.labelWidth),
7589 } else if ( this.fieldLabel.length) {
7595 //cls : 'input-group-addon',
7596 html : this.fieldLabel
7606 Roo.log(" no label && no align");
7616 if (this.disabled) {
7617 input.disabled=true;
7624 * return the real textarea element.
7626 inputEl: function ()
7628 return this.el.select('textarea.form-control',true).first();
7636 * trigger field - base class for combo..
7641 * @class Roo.bootstrap.TriggerField
7642 * @extends Roo.bootstrap.Input
7643 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7644 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7645 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7646 * for which you can provide a custom implementation. For example:
7648 var trigger = new Roo.bootstrap.TriggerField();
7649 trigger.onTriggerClick = myTriggerFn;
7650 trigger.applyTo('my-field');
7653 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7654 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7655 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7656 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7658 * Create a new TriggerField.
7659 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7660 * to the base TextField)
7662 Roo.bootstrap.TriggerField = function(config){
7663 this.mimicing = false;
7664 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7667 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7669 * @cfg {String} triggerClass A CSS class to apply to the trigger
7672 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7676 /** @cfg {Boolean} grow @hide */
7677 /** @cfg {Number} growMin @hide */
7678 /** @cfg {Number} growMax @hide */
7684 autoSize: Roo.emptyFn,
7691 actionMode : 'wrap',
7695 getAutoCreate : function(){
7697 var align = this.labelAlign || this.parentLabelAlign();
7702 cls: 'form-group' //input-group
7709 type : this.inputType,
7710 cls : 'form-control',
7711 autocomplete: 'off',
7712 placeholder : this.placeholder || ''
7716 input.name = this.name;
7719 input.cls += ' input-' + this.size;
7722 if (this.disabled) {
7723 input.disabled=true;
7726 var inputblock = input;
7728 if (this.before || this.after) {
7731 cls : 'input-group',
7735 inputblock.cn.push({
7737 cls : 'input-group-addon',
7741 inputblock.cn.push(input);
7743 inputblock.cn.push({
7745 cls : 'input-group-addon',
7758 cls: 'form-hidden-field'
7766 Roo.log('multiple');
7774 cls: 'form-hidden-field'
7778 cls: 'select2-choices',
7782 cls: 'select2-search-field',
7795 cls: 'select2-container input-group',
7800 // cls: 'typeahead typeahead-long dropdown-menu',
7801 // style: 'display:none'
7806 if(!this.multiple && this.showToggleBtn){
7809 cls : 'input-group-addon btn dropdown-toggle',
7817 cls: 'combobox-clear',
7831 combobox.cls += ' select2-container-multi';
7834 if (align ==='left' && this.fieldLabel.length) {
7836 Roo.log("left and has label");
7842 cls : 'control-label col-sm-' + this.labelWidth,
7843 html : this.fieldLabel
7847 cls : "col-sm-" + (12 - this.labelWidth),
7854 } else if ( this.fieldLabel.length) {
7860 //cls : 'input-group-addon',
7861 html : this.fieldLabel
7871 Roo.log(" no label && no align");
7878 ['xs','sm','md','lg'].map(function(size){
7879 if (settings[size]) {
7880 cfg.cls += ' col-' + size + '-' + settings[size];
7891 onResize : function(w, h){
7892 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7893 // if(typeof w == 'number'){
7894 // var x = w - this.trigger.getWidth();
7895 // this.inputEl().setWidth(this.adjustWidth('input', x));
7896 // this.trigger.setStyle('left', x+'px');
7901 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7904 getResizeEl : function(){
7905 return this.inputEl();
7909 getPositionEl : function(){
7910 return this.inputEl();
7914 alignErrorIcon : function(){
7915 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7919 initEvents : function(){
7923 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7924 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7925 if(!this.multiple && this.showToggleBtn){
7926 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7927 if(this.hideTrigger){
7928 this.trigger.setDisplayed(false);
7930 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7934 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7937 //this.trigger.addClassOnOver('x-form-trigger-over');
7938 //this.trigger.addClassOnClick('x-form-trigger-click');
7941 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7945 createList : function()
7947 this.list = Roo.get(document.body).createChild({
7949 cls: 'typeahead typeahead-long dropdown-menu',
7950 style: 'display:none'
7953 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
7958 initTrigger : function(){
7963 onDestroy : function(){
7965 this.trigger.removeAllListeners();
7966 // this.trigger.remove();
7969 // this.wrap.remove();
7971 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7975 onFocus : function(){
7976 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7979 this.wrap.addClass('x-trigger-wrap-focus');
7980 this.mimicing = true;
7981 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7982 if(this.monitorTab){
7983 this.el.on("keydown", this.checkTab, this);
7990 checkTab : function(e){
7991 if(e.getKey() == e.TAB){
7997 onBlur : function(){
8002 mimicBlur : function(e, t){
8004 if(!this.wrap.contains(t) && this.validateBlur()){
8011 triggerBlur : function(){
8012 this.mimicing = false;
8013 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8014 if(this.monitorTab){
8015 this.el.un("keydown", this.checkTab, this);
8017 //this.wrap.removeClass('x-trigger-wrap-focus');
8018 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8022 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8023 validateBlur : function(e, t){
8028 onDisable : function(){
8029 this.inputEl().dom.disabled = true;
8030 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8032 // this.wrap.addClass('x-item-disabled');
8037 onEnable : function(){
8038 this.inputEl().dom.disabled = false;
8039 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8041 // this.el.removeClass('x-item-disabled');
8046 onShow : function(){
8047 var ae = this.getActionEl();
8050 ae.dom.style.display = '';
8051 ae.dom.style.visibility = 'visible';
8057 onHide : function(){
8058 var ae = this.getActionEl();
8059 ae.dom.style.display = 'none';
8063 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8064 * by an implementing function.
8066 * @param {EventObject} e
8068 onTriggerClick : Roo.emptyFn
8072 * Ext JS Library 1.1.1
8073 * Copyright(c) 2006-2007, Ext JS, LLC.
8075 * Originally Released Under LGPL - original licence link has changed is not relivant.
8078 * <script type="text/javascript">
8083 * @class Roo.data.SortTypes
8085 * Defines the default sorting (casting?) comparison functions used when sorting data.
8087 Roo.data.SortTypes = {
8089 * Default sort that does nothing
8090 * @param {Mixed} s The value being converted
8091 * @return {Mixed} The comparison value
8098 * The regular expression used to strip tags
8102 stripTagsRE : /<\/?[^>]+>/gi,
8105 * Strips all HTML tags to sort on text only
8106 * @param {Mixed} s The value being converted
8107 * @return {String} The comparison value
8109 asText : function(s){
8110 return String(s).replace(this.stripTagsRE, "");
8114 * Strips all HTML tags to sort on text only - Case insensitive
8115 * @param {Mixed} s The value being converted
8116 * @return {String} The comparison value
8118 asUCText : function(s){
8119 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8123 * Case insensitive string
8124 * @param {Mixed} s The value being converted
8125 * @return {String} The comparison value
8127 asUCString : function(s) {
8128 return String(s).toUpperCase();
8133 * @param {Mixed} s The value being converted
8134 * @return {Number} The comparison value
8136 asDate : function(s) {
8140 if(s instanceof Date){
8143 return Date.parse(String(s));
8148 * @param {Mixed} s The value being converted
8149 * @return {Float} The comparison value
8151 asFloat : function(s) {
8152 var val = parseFloat(String(s).replace(/,/g, ""));
8153 if(isNaN(val)) val = 0;
8159 * @param {Mixed} s The value being converted
8160 * @return {Number} The comparison value
8162 asInt : function(s) {
8163 var val = parseInt(String(s).replace(/,/g, ""));
8164 if(isNaN(val)) val = 0;
8169 * Ext JS Library 1.1.1
8170 * Copyright(c) 2006-2007, Ext JS, LLC.
8172 * Originally Released Under LGPL - original licence link has changed is not relivant.
8175 * <script type="text/javascript">
8179 * @class Roo.data.Record
8180 * Instances of this class encapsulate both record <em>definition</em> information, and record
8181 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8182 * to access Records cached in an {@link Roo.data.Store} object.<br>
8184 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8185 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8188 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8190 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8191 * {@link #create}. The parameters are the same.
8192 * @param {Array} data An associative Array of data values keyed by the field name.
8193 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8194 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8195 * not specified an integer id is generated.
8197 Roo.data.Record = function(data, id){
8198 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8203 * Generate a constructor for a specific record layout.
8204 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8205 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8206 * Each field definition object may contain the following properties: <ul>
8207 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
8208 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8209 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8210 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8211 * is being used, then this is a string containing the javascript expression to reference the data relative to
8212 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8213 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8214 * this may be omitted.</p></li>
8215 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8216 * <ul><li>auto (Default, implies no conversion)</li>
8221 * <li>date</li></ul></p></li>
8222 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8223 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8224 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8225 * by the Reader into an object that will be stored in the Record. It is passed the
8226 * following parameters:<ul>
8227 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8229 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8231 * <br>usage:<br><pre><code>
8232 var TopicRecord = Roo.data.Record.create(
8233 {name: 'title', mapping: 'topic_title'},
8234 {name: 'author', mapping: 'username'},
8235 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8236 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8237 {name: 'lastPoster', mapping: 'user2'},
8238 {name: 'excerpt', mapping: 'post_text'}
8241 var myNewRecord = new TopicRecord({
8242 title: 'Do my job please',
8245 lastPost: new Date(),
8246 lastPoster: 'Animal',
8247 excerpt: 'No way dude!'
8249 myStore.add(myNewRecord);
8254 Roo.data.Record.create = function(o){
8256 f.superclass.constructor.apply(this, arguments);
8258 Roo.extend(f, Roo.data.Record);
8259 var p = f.prototype;
8260 p.fields = new Roo.util.MixedCollection(false, function(field){
8263 for(var i = 0, len = o.length; i < len; i++){
8264 p.fields.add(new Roo.data.Field(o[i]));
8266 f.getField = function(name){
8267 return p.fields.get(name);
8272 Roo.data.Record.AUTO_ID = 1000;
8273 Roo.data.Record.EDIT = 'edit';
8274 Roo.data.Record.REJECT = 'reject';
8275 Roo.data.Record.COMMIT = 'commit';
8277 Roo.data.Record.prototype = {
8279 * Readonly flag - true if this record has been modified.
8288 join : function(store){
8293 * Set the named field to the specified value.
8294 * @param {String} name The name of the field to set.
8295 * @param {Object} value The value to set the field to.
8297 set : function(name, value){
8298 if(this.data[name] == value){
8305 if(typeof this.modified[name] == 'undefined'){
8306 this.modified[name] = this.data[name];
8308 this.data[name] = value;
8309 if(!this.editing && this.store){
8310 this.store.afterEdit(this);
8315 * Get the value of the named field.
8316 * @param {String} name The name of the field to get the value of.
8317 * @return {Object} The value of the field.
8319 get : function(name){
8320 return this.data[name];
8324 beginEdit : function(){
8325 this.editing = true;
8330 cancelEdit : function(){
8331 this.editing = false;
8332 delete this.modified;
8336 endEdit : function(){
8337 this.editing = false;
8338 if(this.dirty && this.store){
8339 this.store.afterEdit(this);
8344 * Usually called by the {@link Roo.data.Store} which owns the Record.
8345 * Rejects all changes made to the Record since either creation, or the last commit operation.
8346 * Modified fields are reverted to their original values.
8348 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8349 * of reject operations.
8351 reject : function(){
8352 var m = this.modified;
8354 if(typeof m[n] != "function"){
8355 this.data[n] = m[n];
8359 delete this.modified;
8360 this.editing = false;
8362 this.store.afterReject(this);
8367 * Usually called by the {@link Roo.data.Store} which owns the Record.
8368 * Commits all changes made to the Record since either creation, or the last commit operation.
8370 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8371 * of commit operations.
8373 commit : function(){
8375 delete this.modified;
8376 this.editing = false;
8378 this.store.afterCommit(this);
8383 hasError : function(){
8384 return this.error != null;
8388 clearError : function(){
8393 * Creates a copy of this record.
8394 * @param {String} id (optional) A new record id if you don't want to use this record's id
8397 copy : function(newId) {
8398 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8402 * Ext JS Library 1.1.1
8403 * Copyright(c) 2006-2007, Ext JS, LLC.
8405 * Originally Released Under LGPL - original licence link has changed is not relivant.
8408 * <script type="text/javascript">
8414 * @class Roo.data.Store
8415 * @extends Roo.util.Observable
8416 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8417 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8419 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
8420 * has no knowledge of the format of the data returned by the Proxy.<br>
8422 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8423 * instances from the data object. These records are cached and made available through accessor functions.
8425 * Creates a new Store.
8426 * @param {Object} config A config object containing the objects needed for the Store to access data,
8427 * and read the data into Records.
8429 Roo.data.Store = function(config){
8430 this.data = new Roo.util.MixedCollection(false);
8431 this.data.getKey = function(o){
8434 this.baseParams = {};
8441 "multisort" : "_multisort"
8444 if(config && config.data){
8445 this.inlineData = config.data;
8449 Roo.apply(this, config);
8451 if(this.reader){ // reader passed
8452 this.reader = Roo.factory(this.reader, Roo.data);
8453 this.reader.xmodule = this.xmodule || false;
8454 if(!this.recordType){
8455 this.recordType = this.reader.recordType;
8457 if(this.reader.onMetaChange){
8458 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8462 if(this.recordType){
8463 this.fields = this.recordType.prototype.fields;
8469 * @event datachanged
8470 * Fires when the data cache has changed, and a widget which is using this Store
8471 * as a Record cache should refresh its view.
8472 * @param {Store} this
8477 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8478 * @param {Store} this
8479 * @param {Object} meta The JSON metadata
8484 * Fires when Records have been added to the Store
8485 * @param {Store} this
8486 * @param {Roo.data.Record[]} records The array of Records added
8487 * @param {Number} index The index at which the record(s) were added
8492 * Fires when a Record has been removed from the Store
8493 * @param {Store} this
8494 * @param {Roo.data.Record} record The Record that was removed
8495 * @param {Number} index The index at which the record was removed
8500 * Fires when a Record has been updated
8501 * @param {Store} this
8502 * @param {Roo.data.Record} record The Record that was updated
8503 * @param {String} operation The update operation being performed. Value may be one of:
8505 Roo.data.Record.EDIT
8506 Roo.data.Record.REJECT
8507 Roo.data.Record.COMMIT
8513 * Fires when the data cache has been cleared.
8514 * @param {Store} this
8519 * Fires before a request is made for a new data object. If the beforeload handler returns false
8520 * the load action will be canceled.
8521 * @param {Store} this
8522 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8526 * @event beforeloadadd
8527 * Fires after a new set of Records has been loaded.
8528 * @param {Store} this
8529 * @param {Roo.data.Record[]} records The Records that were loaded
8530 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8532 beforeloadadd : true,
8535 * Fires after a new set of Records has been loaded, before they are added to the store.
8536 * @param {Store} this
8537 * @param {Roo.data.Record[]} records The Records that were loaded
8538 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8539 * @params {Object} return from reader
8543 * @event loadexception
8544 * Fires if an exception occurs in the Proxy during loading.
8545 * Called with the signature of the Proxy's "loadexception" event.
8546 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8549 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8550 * @param {Object} load options
8551 * @param {Object} jsonData from your request (normally this contains the Exception)
8553 loadexception : true
8557 this.proxy = Roo.factory(this.proxy, Roo.data);
8558 this.proxy.xmodule = this.xmodule || false;
8559 this.relayEvents(this.proxy, ["loadexception"]);
8561 this.sortToggle = {};
8562 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8564 Roo.data.Store.superclass.constructor.call(this);
8566 if(this.inlineData){
8567 this.loadData(this.inlineData);
8568 delete this.inlineData;
8572 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8574 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8575 * without a remote query - used by combo/forms at present.
8579 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8582 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8585 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8586 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8589 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8590 * on any HTTP request
8593 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8596 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8600 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8601 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8606 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8607 * loaded or when a record is removed. (defaults to false).
8609 pruneModifiedRecords : false,
8615 * Add Records to the Store and fires the add event.
8616 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8618 add : function(records){
8619 records = [].concat(records);
8620 for(var i = 0, len = records.length; i < len; i++){
8621 records[i].join(this);
8623 var index = this.data.length;
8624 this.data.addAll(records);
8625 this.fireEvent("add", this, records, index);
8629 * Remove a Record from the Store and fires the remove event.
8630 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8632 remove : function(record){
8633 var index = this.data.indexOf(record);
8634 this.data.removeAt(index);
8635 if(this.pruneModifiedRecords){
8636 this.modified.remove(record);
8638 this.fireEvent("remove", this, record, index);
8642 * Remove all Records from the Store and fires the clear event.
8644 removeAll : function(){
8646 if(this.pruneModifiedRecords){
8649 this.fireEvent("clear", this);
8653 * Inserts Records to the Store at the given index and fires the add event.
8654 * @param {Number} index The start index at which to insert the passed Records.
8655 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8657 insert : function(index, records){
8658 records = [].concat(records);
8659 for(var i = 0, len = records.length; i < len; i++){
8660 this.data.insert(index, records[i]);
8661 records[i].join(this);
8663 this.fireEvent("add", this, records, index);
8667 * Get the index within the cache of the passed Record.
8668 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8669 * @return {Number} The index of the passed Record. Returns -1 if not found.
8671 indexOf : function(record){
8672 return this.data.indexOf(record);
8676 * Get the index within the cache of the Record with the passed id.
8677 * @param {String} id The id of the Record to find.
8678 * @return {Number} The index of the Record. Returns -1 if not found.
8680 indexOfId : function(id){
8681 return this.data.indexOfKey(id);
8685 * Get the Record with the specified id.
8686 * @param {String} id The id of the Record to find.
8687 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8689 getById : function(id){
8690 return this.data.key(id);
8694 * Get the Record at the specified index.
8695 * @param {Number} index The index of the Record to find.
8696 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8698 getAt : function(index){
8699 return this.data.itemAt(index);
8703 * Returns a range of Records between specified indices.
8704 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8705 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8706 * @return {Roo.data.Record[]} An array of Records
8708 getRange : function(start, end){
8709 return this.data.getRange(start, end);
8713 storeOptions : function(o){
8714 o = Roo.apply({}, o);
8717 this.lastOptions = o;
8721 * Loads the Record cache from the configured Proxy using the configured Reader.
8723 * If using remote paging, then the first load call must specify the <em>start</em>
8724 * and <em>limit</em> properties in the options.params property to establish the initial
8725 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8727 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8728 * and this call will return before the new data has been loaded. Perform any post-processing
8729 * in a callback function, or in a "load" event handler.</strong>
8731 * @param {Object} options An object containing properties which control loading options:<ul>
8732 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8733 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8734 * passed the following arguments:<ul>
8735 * <li>r : Roo.data.Record[]</li>
8736 * <li>options: Options object from the load call</li>
8737 * <li>success: Boolean success indicator</li></ul></li>
8738 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8739 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8742 load : function(options){
8743 options = options || {};
8744 if(this.fireEvent("beforeload", this, options) !== false){
8745 this.storeOptions(options);
8746 var p = Roo.apply(options.params || {}, this.baseParams);
8747 // if meta was not loaded from remote source.. try requesting it.
8748 if (!this.reader.metaFromRemote) {
8751 if(this.sortInfo && this.remoteSort){
8752 var pn = this.paramNames;
8753 p[pn["sort"]] = this.sortInfo.field;
8754 p[pn["dir"]] = this.sortInfo.direction;
8756 if (this.multiSort) {
8757 var pn = this.paramNames;
8758 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8761 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8766 * Reloads the Record cache from the configured Proxy using the configured Reader and
8767 * the options from the last load operation performed.
8768 * @param {Object} options (optional) An object containing properties which may override the options
8769 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8770 * the most recently used options are reused).
8772 reload : function(options){
8773 this.load(Roo.applyIf(options||{}, this.lastOptions));
8777 // Called as a callback by the Reader during a load operation.
8778 loadRecords : function(o, options, success){
8779 if(!o || success === false){
8780 if(success !== false){
8781 this.fireEvent("load", this, [], options, o);
8783 if(options.callback){
8784 options.callback.call(options.scope || this, [], options, false);
8788 // if data returned failure - throw an exception.
8789 if (o.success === false) {
8790 // show a message if no listener is registered.
8791 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8792 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8794 // loadmask wil be hooked into this..
8795 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8798 var r = o.records, t = o.totalRecords || r.length;
8800 this.fireEvent("beforeloadadd", this, r, options, o);
8802 if(!options || options.add !== true){
8803 if(this.pruneModifiedRecords){
8806 for(var i = 0, len = r.length; i < len; i++){
8810 this.data = this.snapshot;
8811 delete this.snapshot;
8814 this.data.addAll(r);
8815 this.totalLength = t;
8817 this.fireEvent("datachanged", this);
8819 this.totalLength = Math.max(t, this.data.length+r.length);
8822 this.fireEvent("load", this, r, options, o);
8823 if(options.callback){
8824 options.callback.call(options.scope || this, r, options, true);
8830 * Loads data from a passed data block. A Reader which understands the format of the data
8831 * must have been configured in the constructor.
8832 * @param {Object} data The data block from which to read the Records. The format of the data expected
8833 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8834 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8836 loadData : function(o, append){
8837 var r = this.reader.readRecords(o);
8838 this.loadRecords(r, {add: append}, true);
8842 * Gets the number of cached records.
8844 * <em>If using paging, this may not be the total size of the dataset. If the data object
8845 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8846 * the data set size</em>
8848 getCount : function(){
8849 return this.data.length || 0;
8853 * Gets the total number of records in the dataset as returned by the server.
8855 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8856 * the dataset size</em>
8858 getTotalCount : function(){
8859 return this.totalLength || 0;
8863 * Returns the sort state of the Store as an object with two properties:
8865 field {String} The name of the field by which the Records are sorted
8866 direction {String} The sort order, "ASC" or "DESC"
8869 getSortState : function(){
8870 return this.sortInfo;
8874 applySort : function(){
8875 if(this.sortInfo && !this.remoteSort){
8876 var s = this.sortInfo, f = s.field;
8877 var st = this.fields.get(f).sortType;
8878 var fn = function(r1, r2){
8879 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8880 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8882 this.data.sort(s.direction, fn);
8883 if(this.snapshot && this.snapshot != this.data){
8884 this.snapshot.sort(s.direction, fn);
8890 * Sets the default sort column and order to be used by the next load operation.
8891 * @param {String} fieldName The name of the field to sort by.
8892 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8894 setDefaultSort : function(field, dir){
8895 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8900 * If remote sorting is used, the sort is performed on the server, and the cache is
8901 * reloaded. If local sorting is used, the cache is sorted internally.
8902 * @param {String} fieldName The name of the field to sort by.
8903 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8905 sort : function(fieldName, dir){
8906 var f = this.fields.get(fieldName);
8908 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8910 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8911 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8916 this.sortToggle[f.name] = dir;
8917 this.sortInfo = {field: f.name, direction: dir};
8918 if(!this.remoteSort){
8920 this.fireEvent("datachanged", this);
8922 this.load(this.lastOptions);
8927 * Calls the specified function for each of the Records in the cache.
8928 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8929 * Returning <em>false</em> aborts and exits the iteration.
8930 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8932 each : function(fn, scope){
8933 this.data.each(fn, scope);
8937 * Gets all records modified since the last commit. Modified records are persisted across load operations
8938 * (e.g., during paging).
8939 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8941 getModifiedRecords : function(){
8942 return this.modified;
8946 createFilterFn : function(property, value, anyMatch){
8947 if(!value.exec){ // not a regex
8948 value = String(value);
8949 if(value.length == 0){
8952 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8955 return value.test(r.data[property]);
8960 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8961 * @param {String} property A field on your records
8962 * @param {Number} start The record index to start at (defaults to 0)
8963 * @param {Number} end The last record index to include (defaults to length - 1)
8964 * @return {Number} The sum
8966 sum : function(property, start, end){
8967 var rs = this.data.items, v = 0;
8969 end = (end || end === 0) ? end : rs.length-1;
8971 for(var i = start; i <= end; i++){
8972 v += (rs[i].data[property] || 0);
8978 * Filter the records by a specified property.
8979 * @param {String} field A field on your records
8980 * @param {String/RegExp} value Either a string that the field
8981 * should start with or a RegExp to test against the field
8982 * @param {Boolean} anyMatch True to match any part not just the beginning
8984 filter : function(property, value, anyMatch){
8985 var fn = this.createFilterFn(property, value, anyMatch);
8986 return fn ? this.filterBy(fn) : this.clearFilter();
8990 * Filter by a function. The specified function will be called with each
8991 * record in this data source. If the function returns true the record is included,
8992 * otherwise it is filtered.
8993 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8994 * @param {Object} scope (optional) The scope of the function (defaults to this)
8996 filterBy : function(fn, scope){
8997 this.snapshot = this.snapshot || this.data;
8998 this.data = this.queryBy(fn, scope||this);
8999 this.fireEvent("datachanged", this);
9003 * Query the records by a specified property.
9004 * @param {String} field A field on your records
9005 * @param {String/RegExp} value Either a string that the field
9006 * should start with or a RegExp to test against the field
9007 * @param {Boolean} anyMatch True to match any part not just the beginning
9008 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9010 query : function(property, value, anyMatch){
9011 var fn = this.createFilterFn(property, value, anyMatch);
9012 return fn ? this.queryBy(fn) : this.data.clone();
9016 * Query by a function. The specified function will be called with each
9017 * record in this data source. If the function returns true the record is included
9019 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9020 * @param {Object} scope (optional) The scope of the function (defaults to this)
9021 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9023 queryBy : function(fn, scope){
9024 var data = this.snapshot || this.data;
9025 return data.filterBy(fn, scope||this);
9029 * Collects unique values for a particular dataIndex from this store.
9030 * @param {String} dataIndex The property to collect
9031 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9032 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9033 * @return {Array} An array of the unique values
9035 collect : function(dataIndex, allowNull, bypassFilter){
9036 var d = (bypassFilter === true && this.snapshot) ?
9037 this.snapshot.items : this.data.items;
9038 var v, sv, r = [], l = {};
9039 for(var i = 0, len = d.length; i < len; i++){
9040 v = d[i].data[dataIndex];
9042 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9051 * Revert to a view of the Record cache with no filtering applied.
9052 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9054 clearFilter : function(suppressEvent){
9055 if(this.snapshot && this.snapshot != this.data){
9056 this.data = this.snapshot;
9057 delete this.snapshot;
9058 if(suppressEvent !== true){
9059 this.fireEvent("datachanged", this);
9065 afterEdit : function(record){
9066 if(this.modified.indexOf(record) == -1){
9067 this.modified.push(record);
9069 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9073 afterReject : function(record){
9074 this.modified.remove(record);
9075 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9079 afterCommit : function(record){
9080 this.modified.remove(record);
9081 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9085 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9086 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9088 commitChanges : function(){
9089 var m = this.modified.slice(0);
9091 for(var i = 0, len = m.length; i < len; i++){
9097 * Cancel outstanding changes on all changed records.
9099 rejectChanges : function(){
9100 var m = this.modified.slice(0);
9102 for(var i = 0, len = m.length; i < len; i++){
9107 onMetaChange : function(meta, rtype, o){
9108 this.recordType = rtype;
9109 this.fields = rtype.prototype.fields;
9110 delete this.snapshot;
9111 this.sortInfo = meta.sortInfo || this.sortInfo;
9113 this.fireEvent('metachange', this, this.reader.meta);
9116 moveIndex : function(data, type)
9118 var index = this.indexOf(data);
9120 var newIndex = index + type;
9124 this.insert(newIndex, data);
9129 * Ext JS Library 1.1.1
9130 * Copyright(c) 2006-2007, Ext JS, LLC.
9132 * Originally Released Under LGPL - original licence link has changed is not relivant.
9135 * <script type="text/javascript">
9139 * @class Roo.data.SimpleStore
9140 * @extends Roo.data.Store
9141 * Small helper class to make creating Stores from Array data easier.
9142 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9143 * @cfg {Array} fields An array of field definition objects, or field name strings.
9144 * @cfg {Array} data The multi-dimensional array of data
9146 * @param {Object} config
9148 Roo.data.SimpleStore = function(config){
9149 Roo.data.SimpleStore.superclass.constructor.call(this, {
9151 reader: new Roo.data.ArrayReader({
9154 Roo.data.Record.create(config.fields)
9156 proxy : new Roo.data.MemoryProxy(config.data)
9160 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9162 * Ext JS Library 1.1.1
9163 * Copyright(c) 2006-2007, Ext JS, LLC.
9165 * Originally Released Under LGPL - original licence link has changed is not relivant.
9168 * <script type="text/javascript">
9173 * @extends Roo.data.Store
9174 * @class Roo.data.JsonStore
9175 * Small helper class to make creating Stores for JSON data easier. <br/>
9177 var store = new Roo.data.JsonStore({
9178 url: 'get-images.php',
9180 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9183 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9184 * JsonReader and HttpProxy (unless inline data is provided).</b>
9185 * @cfg {Array} fields An array of field definition objects, or field name strings.
9187 * @param {Object} config
9189 Roo.data.JsonStore = function(c){
9190 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9191 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9192 reader: new Roo.data.JsonReader(c, c.fields)
9195 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9197 * Ext JS Library 1.1.1
9198 * Copyright(c) 2006-2007, Ext JS, LLC.
9200 * Originally Released Under LGPL - original licence link has changed is not relivant.
9203 * <script type="text/javascript">
9207 Roo.data.Field = function(config){
9208 if(typeof config == "string"){
9209 config = {name: config};
9211 Roo.apply(this, config);
9217 var st = Roo.data.SortTypes;
9218 // named sortTypes are supported, here we look them up
9219 if(typeof this.sortType == "string"){
9220 this.sortType = st[this.sortType];
9223 // set default sortType for strings and dates
9227 this.sortType = st.asUCString;
9230 this.sortType = st.asDate;
9233 this.sortType = st.none;
9238 var stripRe = /[\$,%]/g;
9240 // prebuilt conversion function for this field, instead of
9241 // switching every time we're reading a value
9243 var cv, dateFormat = this.dateFormat;
9248 cv = function(v){ return v; };
9251 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9255 return v !== undefined && v !== null && v !== '' ?
9256 parseInt(String(v).replace(stripRe, ""), 10) : '';
9261 return v !== undefined && v !== null && v !== '' ?
9262 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9267 cv = function(v){ return v === true || v === "true" || v == 1; };
9274 if(v instanceof Date){
9278 if(dateFormat == "timestamp"){
9279 return new Date(v*1000);
9281 return Date.parseDate(v, dateFormat);
9283 var parsed = Date.parse(v);
9284 return parsed ? new Date(parsed) : null;
9293 Roo.data.Field.prototype = {
9301 * Ext JS Library 1.1.1
9302 * Copyright(c) 2006-2007, Ext JS, LLC.
9304 * Originally Released Under LGPL - original licence link has changed is not relivant.
9307 * <script type="text/javascript">
9310 // Base class for reading structured data from a data source. This class is intended to be
9311 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9314 * @class Roo.data.DataReader
9315 * Base class for reading structured data from a data source. This class is intended to be
9316 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9319 Roo.data.DataReader = function(meta, recordType){
9323 this.recordType = recordType instanceof Array ?
9324 Roo.data.Record.create(recordType) : recordType;
9327 Roo.data.DataReader.prototype = {
9329 * Create an empty record
9330 * @param {Object} data (optional) - overlay some values
9331 * @return {Roo.data.Record} record created.
9333 newRow : function(d) {
9335 this.recordType.prototype.fields.each(function(c) {
9337 case 'int' : da[c.name] = 0; break;
9338 case 'date' : da[c.name] = new Date(); break;
9339 case 'float' : da[c.name] = 0.0; break;
9340 case 'boolean' : da[c.name] = false; break;
9341 default : da[c.name] = ""; break;
9345 return new this.recordType(Roo.apply(da, d));
9350 * Ext JS Library 1.1.1
9351 * Copyright(c) 2006-2007, Ext JS, LLC.
9353 * Originally Released Under LGPL - original licence link has changed is not relivant.
9356 * <script type="text/javascript">
9360 * @class Roo.data.DataProxy
9361 * @extends Roo.data.Observable
9362 * This class is an abstract base class for implementations which provide retrieval of
9363 * unformatted data objects.<br>
9365 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9366 * (of the appropriate type which knows how to parse the data object) to provide a block of
9367 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9369 * Custom implementations must implement the load method as described in
9370 * {@link Roo.data.HttpProxy#load}.
9372 Roo.data.DataProxy = function(){
9376 * Fires before a network request is made to retrieve a data object.
9377 * @param {Object} This DataProxy object.
9378 * @param {Object} params The params parameter to the load function.
9383 * Fires before the load method's callback is called.
9384 * @param {Object} This DataProxy object.
9385 * @param {Object} o The data object.
9386 * @param {Object} arg The callback argument object passed to the load function.
9390 * @event loadexception
9391 * Fires if an Exception occurs during data retrieval.
9392 * @param {Object} This DataProxy object.
9393 * @param {Object} o The data object.
9394 * @param {Object} arg The callback argument object passed to the load function.
9395 * @param {Object} e The Exception.
9397 loadexception : true
9399 Roo.data.DataProxy.superclass.constructor.call(this);
9402 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9405 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9409 * Ext JS Library 1.1.1
9410 * Copyright(c) 2006-2007, Ext JS, LLC.
9412 * Originally Released Under LGPL - original licence link has changed is not relivant.
9415 * <script type="text/javascript">
9418 * @class Roo.data.MemoryProxy
9419 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9420 * to the Reader when its load method is called.
9422 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9424 Roo.data.MemoryProxy = function(data){
9428 Roo.data.MemoryProxy.superclass.constructor.call(this);
9432 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9434 * Load data from the requested source (in this case an in-memory
9435 * data object passed to the constructor), read the data object into
9436 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9437 * process that block using the passed callback.
9438 * @param {Object} params This parameter is not used by the MemoryProxy class.
9439 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9440 * object into a block of Roo.data.Records.
9441 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9442 * The function must be passed <ul>
9443 * <li>The Record block object</li>
9444 * <li>The "arg" argument from the load function</li>
9445 * <li>A boolean success indicator</li>
9447 * @param {Object} scope The scope in which to call the callback
9448 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9450 load : function(params, reader, callback, scope, arg){
9451 params = params || {};
9454 result = reader.readRecords(this.data);
9456 this.fireEvent("loadexception", this, arg, null, e);
9457 callback.call(scope, null, arg, false);
9460 callback.call(scope, result, arg, true);
9464 update : function(params, records){
9469 * Ext JS Library 1.1.1
9470 * Copyright(c) 2006-2007, Ext JS, LLC.
9472 * Originally Released Under LGPL - original licence link has changed is not relivant.
9475 * <script type="text/javascript">
9478 * @class Roo.data.HttpProxy
9479 * @extends Roo.data.DataProxy
9480 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9481 * configured to reference a certain URL.<br><br>
9483 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9484 * from which the running page was served.<br><br>
9486 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9488 * Be aware that to enable the browser to parse an XML document, the server must set
9489 * the Content-Type header in the HTTP response to "text/xml".
9491 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9492 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9493 * will be used to make the request.
9495 Roo.data.HttpProxy = function(conn){
9496 Roo.data.HttpProxy.superclass.constructor.call(this);
9497 // is conn a conn config or a real conn?
9499 this.useAjax = !conn || !conn.events;
9503 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9504 // thse are take from connection...
9507 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9510 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9511 * extra parameters to each request made by this object. (defaults to undefined)
9514 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9515 * to each request made by this object. (defaults to undefined)
9518 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
9521 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9524 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9530 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9534 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9535 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9536 * a finer-grained basis than the DataProxy events.
9538 getConnection : function(){
9539 return this.useAjax ? Roo.Ajax : this.conn;
9543 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9544 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9545 * process that block using the passed callback.
9546 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9547 * for the request to the remote server.
9548 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9549 * object into a block of Roo.data.Records.
9550 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9551 * The function must be passed <ul>
9552 * <li>The Record block object</li>
9553 * <li>The "arg" argument from the load function</li>
9554 * <li>A boolean success indicator</li>
9556 * @param {Object} scope The scope in which to call the callback
9557 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9559 load : function(params, reader, callback, scope, arg){
9560 if(this.fireEvent("beforeload", this, params) !== false){
9562 params : params || {},
9564 callback : callback,
9569 callback : this.loadResponse,
9573 Roo.applyIf(o, this.conn);
9574 if(this.activeRequest){
9575 Roo.Ajax.abort(this.activeRequest);
9577 this.activeRequest = Roo.Ajax.request(o);
9579 this.conn.request(o);
9582 callback.call(scope||this, null, arg, false);
9587 loadResponse : function(o, success, response){
9588 delete this.activeRequest;
9590 this.fireEvent("loadexception", this, o, response);
9591 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9596 result = o.reader.read(response);
9598 this.fireEvent("loadexception", this, o, response, e);
9599 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9603 this.fireEvent("load", this, o, o.request.arg);
9604 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9608 update : function(dataSet){
9613 updateResponse : function(dataSet){
9618 * Ext JS Library 1.1.1
9619 * Copyright(c) 2006-2007, Ext JS, LLC.
9621 * Originally Released Under LGPL - original licence link has changed is not relivant.
9624 * <script type="text/javascript">
9628 * @class Roo.data.ScriptTagProxy
9629 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9630 * other than the originating domain of the running page.<br><br>
9632 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
9633 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9635 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9636 * source code that is used as the source inside a <script> tag.<br><br>
9638 * In order for the browser to process the returned data, the server must wrap the data object
9639 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9640 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9641 * depending on whether the callback name was passed:
9644 boolean scriptTag = false;
9645 String cb = request.getParameter("callback");
9648 response.setContentType("text/javascript");
9650 response.setContentType("application/x-json");
9652 Writer out = response.getWriter();
9654 out.write(cb + "(");
9656 out.print(dataBlock.toJsonString());
9663 * @param {Object} config A configuration object.
9665 Roo.data.ScriptTagProxy = function(config){
9666 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9667 Roo.apply(this, config);
9668 this.head = document.getElementsByTagName("head")[0];
9671 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9673 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9675 * @cfg {String} url The URL from which to request the data object.
9678 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9682 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9683 * the server the name of the callback function set up by the load call to process the returned data object.
9684 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9685 * javascript output which calls this named function passing the data object as its only parameter.
9687 callbackParam : "callback",
9689 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9690 * name to the request.
9695 * Load data from the configured URL, read the data object into
9696 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9697 * process that block using the passed callback.
9698 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9699 * for the request to the remote server.
9700 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9701 * object into a block of Roo.data.Records.
9702 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9703 * The function must be passed <ul>
9704 * <li>The Record block object</li>
9705 * <li>The "arg" argument from the load function</li>
9706 * <li>A boolean success indicator</li>
9708 * @param {Object} scope The scope in which to call the callback
9709 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9711 load : function(params, reader, callback, scope, arg){
9712 if(this.fireEvent("beforeload", this, params) !== false){
9714 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9717 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9719 url += "&_dc=" + (new Date().getTime());
9721 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9724 cb : "stcCallback"+transId,
9725 scriptId : "stcScript"+transId,
9729 callback : callback,
9735 window[trans.cb] = function(o){
9736 conn.handleResponse(o, trans);
9739 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9741 if(this.autoAbort !== false){
9745 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9747 var script = document.createElement("script");
9748 script.setAttribute("src", url);
9749 script.setAttribute("type", "text/javascript");
9750 script.setAttribute("id", trans.scriptId);
9751 this.head.appendChild(script);
9755 callback.call(scope||this, null, arg, false);
9760 isLoading : function(){
9761 return this.trans ? true : false;
9765 * Abort the current server request.
9768 if(this.isLoading()){
9769 this.destroyTrans(this.trans);
9774 destroyTrans : function(trans, isLoaded){
9775 this.head.removeChild(document.getElementById(trans.scriptId));
9776 clearTimeout(trans.timeoutId);
9778 window[trans.cb] = undefined;
9780 delete window[trans.cb];
9783 // if hasn't been loaded, wait for load to remove it to prevent script error
9784 window[trans.cb] = function(){
9785 window[trans.cb] = undefined;
9787 delete window[trans.cb];
9794 handleResponse : function(o, trans){
9796 this.destroyTrans(trans, true);
9799 result = trans.reader.readRecords(o);
9801 this.fireEvent("loadexception", this, o, trans.arg, e);
9802 trans.callback.call(trans.scope||window, null, trans.arg, false);
9805 this.fireEvent("load", this, o, trans.arg);
9806 trans.callback.call(trans.scope||window, result, trans.arg, true);
9810 handleFailure : function(trans){
9812 this.destroyTrans(trans, false);
9813 this.fireEvent("loadexception", this, null, trans.arg);
9814 trans.callback.call(trans.scope||window, null, trans.arg, false);
9818 * Ext JS Library 1.1.1
9819 * Copyright(c) 2006-2007, Ext JS, LLC.
9821 * Originally Released Under LGPL - original licence link has changed is not relivant.
9824 * <script type="text/javascript">
9828 * @class Roo.data.JsonReader
9829 * @extends Roo.data.DataReader
9830 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9831 * based on mappings in a provided Roo.data.Record constructor.
9833 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9834 * in the reply previously.
9839 var RecordDef = Roo.data.Record.create([
9840 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9841 {name: 'occupation'} // This field will use "occupation" as the mapping.
9843 var myReader = new Roo.data.JsonReader({
9844 totalProperty: "results", // The property which contains the total dataset size (optional)
9845 root: "rows", // The property which contains an Array of row objects
9846 id: "id" // The property within each row object that provides an ID for the record (optional)
9850 * This would consume a JSON file like this:
9852 { 'results': 2, 'rows': [
9853 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9854 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9857 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9858 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9859 * paged from the remote server.
9860 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9861 * @cfg {String} root name of the property which contains the Array of row objects.
9862 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9864 * Create a new JsonReader
9865 * @param {Object} meta Metadata configuration options
9866 * @param {Object} recordType Either an Array of field definition objects,
9867 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9869 Roo.data.JsonReader = function(meta, recordType){
9872 // set some defaults:
9874 totalProperty: 'total',
9875 successProperty : 'success',
9880 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9882 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9885 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9886 * Used by Store query builder to append _requestMeta to params.
9889 metaFromRemote : false,
9891 * This method is only used by a DataProxy which has retrieved data from a remote server.
9892 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9893 * @return {Object} data A data block which is used by an Roo.data.Store object as
9894 * a cache of Roo.data.Records.
9896 read : function(response){
9897 var json = response.responseText;
9899 var o = /* eval:var:o */ eval("("+json+")");
9901 throw {message: "JsonReader.read: Json object not found"};
9907 this.metaFromRemote = true;
9908 this.meta = o.metaData;
9909 this.recordType = Roo.data.Record.create(o.metaData.fields);
9910 this.onMetaChange(this.meta, this.recordType, o);
9912 return this.readRecords(o);
9915 // private function a store will implement
9916 onMetaChange : function(meta, recordType, o){
9923 simpleAccess: function(obj, subsc) {
9930 getJsonAccessor: function(){
9932 return function(expr) {
9934 return(re.test(expr))
9935 ? new Function("obj", "return obj." + expr)
9945 * Create a data block containing Roo.data.Records from an XML document.
9946 * @param {Object} o An object which contains an Array of row objects in the property specified
9947 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9948 * which contains the total size of the dataset.
9949 * @return {Object} data A data block which is used by an Roo.data.Store object as
9950 * a cache of Roo.data.Records.
9952 readRecords : function(o){
9954 * After any data loads, the raw JSON data is available for further custom processing.
9958 var s = this.meta, Record = this.recordType,
9959 f = Record.prototype.fields, fi = f.items, fl = f.length;
9961 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9963 if(s.totalProperty) {
9964 this.getTotal = this.getJsonAccessor(s.totalProperty);
9966 if(s.successProperty) {
9967 this.getSuccess = this.getJsonAccessor(s.successProperty);
9969 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9971 var g = this.getJsonAccessor(s.id);
9972 this.getId = function(rec) {
9974 return (r === undefined || r === "") ? null : r;
9977 this.getId = function(){return null;};
9980 for(var jj = 0; jj < fl; jj++){
9982 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9983 this.ef[jj] = this.getJsonAccessor(map);
9987 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9988 if(s.totalProperty){
9989 var vt = parseInt(this.getTotal(o), 10);
9994 if(s.successProperty){
9995 var vs = this.getSuccess(o);
9996 if(vs === false || vs === 'false'){
10001 for(var i = 0; i < c; i++){
10004 var id = this.getId(n);
10005 for(var j = 0; j < fl; j++){
10007 var v = this.ef[j](n);
10009 Roo.log('missing convert for ' + f.name);
10013 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10015 var record = new Record(values, id);
10017 records[i] = record;
10023 totalRecords : totalRecords
10028 * Ext JS Library 1.1.1
10029 * Copyright(c) 2006-2007, Ext JS, LLC.
10031 * Originally Released Under LGPL - original licence link has changed is not relivant.
10034 * <script type="text/javascript">
10038 * @class Roo.data.ArrayReader
10039 * @extends Roo.data.DataReader
10040 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10041 * Each element of that Array represents a row of data fields. The
10042 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10043 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10047 var RecordDef = Roo.data.Record.create([
10048 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10049 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10051 var myReader = new Roo.data.ArrayReader({
10052 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10056 * This would consume an Array like this:
10058 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10060 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10062 * Create a new JsonReader
10063 * @param {Object} meta Metadata configuration options.
10064 * @param {Object} recordType Either an Array of field definition objects
10065 * as specified to {@link Roo.data.Record#create},
10066 * or an {@link Roo.data.Record} object
10067 * created using {@link Roo.data.Record#create}.
10069 Roo.data.ArrayReader = function(meta, recordType){
10070 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10073 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10075 * Create a data block containing Roo.data.Records from an XML document.
10076 * @param {Object} o An Array of row objects which represents the dataset.
10077 * @return {Object} data A data block which is used by an Roo.data.Store object as
10078 * a cache of Roo.data.Records.
10080 readRecords : function(o){
10081 var sid = this.meta ? this.meta.id : null;
10082 var recordType = this.recordType, fields = recordType.prototype.fields;
10085 for(var i = 0; i < root.length; i++){
10088 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10089 for(var j = 0, jlen = fields.length; j < jlen; j++){
10090 var f = fields.items[j];
10091 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10092 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10094 values[f.name] = v;
10096 var record = new recordType(values, id);
10098 records[records.length] = record;
10102 totalRecords : records.length
10111 * @class Roo.bootstrap.ComboBox
10112 * @extends Roo.bootstrap.TriggerField
10113 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10114 * @cfg {Boolean} append (true|false) default false
10115 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10116 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10117 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10118 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10119 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10121 * Create a new ComboBox.
10122 * @param {Object} config Configuration options
10124 Roo.bootstrap.ComboBox = function(config){
10125 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10129 * Fires when the dropdown list is expanded
10130 * @param {Roo.bootstrap.ComboBox} combo This combo box
10135 * Fires when the dropdown list is collapsed
10136 * @param {Roo.bootstrap.ComboBox} combo This combo box
10140 * @event beforeselect
10141 * Fires before a list item is selected. Return false to cancel the selection.
10142 * @param {Roo.bootstrap.ComboBox} combo This combo box
10143 * @param {Roo.data.Record} record The data record returned from the underlying store
10144 * @param {Number} index The index of the selected item in the dropdown list
10146 'beforeselect' : true,
10149 * Fires when a list item is selected
10150 * @param {Roo.bootstrap.ComboBox} combo This combo box
10151 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10152 * @param {Number} index The index of the selected item in the dropdown list
10156 * @event beforequery
10157 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10158 * The event object passed has these properties:
10159 * @param {Roo.bootstrap.ComboBox} combo This combo box
10160 * @param {String} query The query
10161 * @param {Boolean} forceAll true to force "all" query
10162 * @param {Boolean} cancel true to cancel the query
10163 * @param {Object} e The query event object
10165 'beforequery': true,
10168 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10169 * @param {Roo.bootstrap.ComboBox} combo This combo box
10174 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10175 * @param {Roo.bootstrap.ComboBox} combo This combo box
10176 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10181 * Fires when the remove value from the combobox array
10182 * @param {Roo.bootstrap.ComboBox} combo This combo box
10189 this.tickItems = [];
10191 this.selectedIndex = -1;
10192 if(this.mode == 'local'){
10193 if(config.queryDelay === undefined){
10194 this.queryDelay = 10;
10196 if(config.minChars === undefined){
10202 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10205 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10206 * rendering into an Roo.Editor, defaults to false)
10209 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10210 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10213 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10216 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10217 * the dropdown list (defaults to undefined, with no header element)
10221 * @cfg {String/Roo.Template} tpl The template to use to render the output
10225 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10227 listWidth: undefined,
10229 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10230 * mode = 'remote' or 'text' if mode = 'local')
10232 displayField: undefined,
10234 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10235 * mode = 'remote' or 'value' if mode = 'local').
10236 * Note: use of a valueField requires the user make a selection
10237 * in order for a value to be mapped.
10239 valueField: undefined,
10243 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10244 * field's data value (defaults to the underlying DOM element's name)
10246 hiddenName: undefined,
10248 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10252 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10254 selectedClass: 'active',
10257 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10261 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10262 * anchor positions (defaults to 'tl-bl')
10264 listAlign: 'tl-bl?',
10266 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10270 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10271 * query specified by the allQuery config option (defaults to 'query')
10273 triggerAction: 'query',
10275 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10276 * (defaults to 4, does not apply if editable = false)
10280 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10281 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10285 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10286 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10290 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10291 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10295 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10296 * when editable = true (defaults to false)
10298 selectOnFocus:false,
10300 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10302 queryParam: 'query',
10304 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10305 * when mode = 'remote' (defaults to 'Loading...')
10307 loadingText: 'Loading...',
10309 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10313 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10317 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10318 * traditional select (defaults to true)
10322 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10326 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10330 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10331 * listWidth has a higher value)
10335 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10336 * allow the user to set arbitrary text into the field (defaults to false)
10338 forceSelection:false,
10340 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10341 * if typeAhead = true (defaults to 250)
10343 typeAheadDelay : 250,
10345 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10346 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10348 valueNotFoundText : undefined,
10350 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10352 blockFocus : false,
10355 * @cfg {Boolean} disableClear Disable showing of clear button.
10357 disableClear : false,
10359 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10361 alwaysQuery : false,
10364 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10378 btnPosition : 'right',
10379 triggerList : true,
10380 showToggleBtn : true,
10381 // element that contains real text value.. (when hidden is used..)
10383 getAutoCreate : function()
10390 if(!this.tickable){
10391 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10396 * ComboBox with tickable selections
10399 var align = this.labelAlign || this.parentLabelAlign();
10402 cls : 'form-group roo-combobox-tickable' //input-group
10408 cls : 'tickable-buttons',
10413 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10420 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10427 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10434 Roo.each(buttons.cn, function(c){
10436 c.cls += ' btn-' + _this.size;
10439 if (_this.disabled) {
10450 cls: 'form-hidden-field'
10454 cls: 'select2-choices',
10458 cls: 'select2-search-field',
10470 cls: 'select2-container input-group select2-container-multi',
10475 // cls: 'typeahead typeahead-long dropdown-menu',
10476 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10481 if (align ==='left' && this.fieldLabel.length) {
10483 Roo.log("left and has label");
10489 cls : 'control-label col-sm-' + this.labelWidth,
10490 html : this.fieldLabel
10494 cls : "col-sm-" + (12 - this.labelWidth),
10501 } else if ( this.fieldLabel.length) {
10507 //cls : 'input-group-addon',
10508 html : this.fieldLabel
10518 Roo.log(" no label && no align");
10525 ['xs','sm','md','lg'].map(function(size){
10526 if (settings[size]) {
10527 cfg.cls += ' col-' + size + '-' + settings[size];
10536 initEvents: function()
10540 throw "can not find store for combo";
10542 this.store = Roo.factory(this.store, Roo.data);
10545 this.initTickableEvents();
10549 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10551 if(this.hiddenName){
10553 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10555 this.hiddenField.dom.value =
10556 this.hiddenValue !== undefined ? this.hiddenValue :
10557 this.value !== undefined ? this.value : '';
10559 // prevent input submission
10560 this.el.dom.removeAttribute('name');
10561 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10566 // this.el.dom.setAttribute('autocomplete', 'off');
10569 var cls = 'x-combo-list';
10571 //this.list = new Roo.Layer({
10572 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10578 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10579 _this.list.setWidth(lw);
10582 this.list.on('mouseover', this.onViewOver, this);
10583 this.list.on('mousemove', this.onViewMove, this);
10585 this.list.on('scroll', this.onViewScroll, this);
10588 this.list.swallowEvent('mousewheel');
10589 this.assetHeight = 0;
10592 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10593 this.assetHeight += this.header.getHeight();
10596 this.innerList = this.list.createChild({cls:cls+'-inner'});
10597 this.innerList.on('mouseover', this.onViewOver, this);
10598 this.innerList.on('mousemove', this.onViewMove, this);
10599 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10601 if(this.allowBlank && !this.pageSize && !this.disableClear){
10602 this.footer = this.list.createChild({cls:cls+'-ft'});
10603 this.pageTb = new Roo.Toolbar(this.footer);
10607 this.footer = this.list.createChild({cls:cls+'-ft'});
10608 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10609 {pageSize: this.pageSize});
10613 if (this.pageTb && this.allowBlank && !this.disableClear) {
10615 this.pageTb.add(new Roo.Toolbar.Fill(), {
10616 cls: 'x-btn-icon x-btn-clear',
10618 handler: function()
10621 _this.clearValue();
10622 _this.onSelect(false, -1);
10627 this.assetHeight += this.footer.getHeight();
10632 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10635 this.view = new Roo.View(this.list, this.tpl, {
10636 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10638 //this.view.wrapEl.setDisplayed(false);
10639 this.view.on('click', this.onViewClick, this);
10643 this.store.on('beforeload', this.onBeforeLoad, this);
10644 this.store.on('load', this.onLoad, this);
10645 this.store.on('loadexception', this.onLoadException, this);
10647 if(this.resizable){
10648 this.resizer = new Roo.Resizable(this.list, {
10649 pinned:true, handles:'se'
10651 this.resizer.on('resize', function(r, w, h){
10652 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10653 this.listWidth = w;
10654 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10655 this.restrictHeight();
10657 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10660 if(!this.editable){
10661 this.editable = true;
10662 this.setEditable(false);
10667 if (typeof(this.events.add.listeners) != 'undefined') {
10669 this.addicon = this.wrap.createChild(
10670 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10672 this.addicon.on('click', function(e) {
10673 this.fireEvent('add', this);
10676 if (typeof(this.events.edit.listeners) != 'undefined') {
10678 this.editicon = this.wrap.createChild(
10679 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10680 if (this.addicon) {
10681 this.editicon.setStyle('margin-left', '40px');
10683 this.editicon.on('click', function(e) {
10685 // we fire even if inothing is selected..
10686 this.fireEvent('edit', this, this.lastData );
10692 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10693 "up" : function(e){
10694 this.inKeyMode = true;
10698 "down" : function(e){
10699 if(!this.isExpanded()){
10700 this.onTriggerClick();
10702 this.inKeyMode = true;
10707 "enter" : function(e){
10708 // this.onViewClick();
10712 if(this.fireEvent("specialkey", this, e)){
10713 this.onViewClick(false);
10719 "esc" : function(e){
10723 "tab" : function(e){
10726 if(this.fireEvent("specialkey", this, e)){
10727 this.onViewClick(false);
10735 doRelay : function(foo, bar, hname){
10736 if(hname == 'down' || this.scope.isExpanded()){
10737 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10746 this.queryDelay = Math.max(this.queryDelay || 10,
10747 this.mode == 'local' ? 10 : 250);
10750 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10752 if(this.typeAhead){
10753 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10755 if(this.editable !== false){
10756 this.inputEl().on("keyup", this.onKeyUp, this);
10758 if(this.forceSelection){
10759 this.inputEl().on('blur', this.doForce, this);
10763 this.choices = this.el.select('ul.select2-choices', true).first();
10764 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10768 initTickableEvents: function()
10772 if(this.hiddenName){
10774 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10776 this.hiddenField.dom.value =
10777 this.hiddenValue !== undefined ? this.hiddenValue :
10778 this.value !== undefined ? this.value : '';
10780 // prevent input submission
10781 this.el.dom.removeAttribute('name');
10782 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10787 // this.list = this.el.select('ul.dropdown-menu',true).first();
10789 this.choices = this.el.select('ul.select2-choices', true).first();
10790 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10791 if(this.triggerList){
10792 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10795 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10796 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10798 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10799 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10801 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10802 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10804 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10805 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10806 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10809 this.cancelBtn.hide();
10814 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10815 _this.list.setWidth(lw);
10818 this.list.on('mouseover', this.onViewOver, this);
10819 this.list.on('mousemove', this.onViewMove, this);
10821 this.list.on('scroll', this.onViewScroll, this);
10824 this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
10827 this.view = new Roo.View(this.list, this.tpl, {
10828 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10831 //this.view.wrapEl.setDisplayed(false);
10832 this.view.on('click', this.onViewClick, this);
10836 this.store.on('beforeload', this.onBeforeLoad, this);
10837 this.store.on('load', this.onLoad, this);
10838 this.store.on('loadexception', this.onLoadException, this);
10840 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10841 // "up" : function(e){
10842 // this.inKeyMode = true;
10843 // this.selectPrev();
10846 // "down" : function(e){
10847 // if(!this.isExpanded()){
10848 // this.onTriggerClick();
10850 // this.inKeyMode = true;
10851 // this.selectNext();
10855 // "enter" : function(e){
10856 //// this.onViewClick();
10858 // this.collapse();
10860 // if(this.fireEvent("specialkey", this, e)){
10861 // this.onViewClick(false);
10867 // "esc" : function(e){
10868 // this.collapse();
10871 // "tab" : function(e){
10872 // this.collapse();
10874 // if(this.fireEvent("specialkey", this, e)){
10875 // this.onViewClick(false);
10883 // doRelay : function(foo, bar, hname){
10884 // if(hname == 'down' || this.scope.isExpanded()){
10885 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10890 // forceKeyDown: true
10894 this.queryDelay = Math.max(this.queryDelay || 10,
10895 this.mode == 'local' ? 10 : 250);
10898 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10900 if(this.typeAhead){
10901 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10905 onDestroy : function(){
10907 this.view.setStore(null);
10908 this.view.el.removeAllListeners();
10909 this.view.el.remove();
10910 this.view.purgeListeners();
10913 this.list.dom.innerHTML = '';
10917 this.store.un('beforeload', this.onBeforeLoad, this);
10918 this.store.un('load', this.onLoad, this);
10919 this.store.un('loadexception', this.onLoadException, this);
10921 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10925 fireKey : function(e){
10926 if(e.isNavKeyPress() && !this.list.isVisible()){
10927 this.fireEvent("specialkey", this, e);
10932 onResize: function(w, h){
10933 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10935 // if(typeof w != 'number'){
10936 // // we do not handle it!?!?
10939 // var tw = this.trigger.getWidth();
10940 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10941 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10943 // this.inputEl().setWidth( this.adjustWidth('input', x));
10945 // //this.trigger.setStyle('left', x+'px');
10947 // if(this.list && this.listWidth === undefined){
10948 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10949 // this.list.setWidth(lw);
10950 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10958 * Allow or prevent the user from directly editing the field text. If false is passed,
10959 * the user will only be able to select from the items defined in the dropdown list. This method
10960 * is the runtime equivalent of setting the 'editable' config option at config time.
10961 * @param {Boolean} value True to allow the user to directly edit the field text
10963 setEditable : function(value){
10964 if(value == this.editable){
10967 this.editable = value;
10969 this.inputEl().dom.setAttribute('readOnly', true);
10970 this.inputEl().on('mousedown', this.onTriggerClick, this);
10971 this.inputEl().addClass('x-combo-noedit');
10973 this.inputEl().dom.setAttribute('readOnly', false);
10974 this.inputEl().un('mousedown', this.onTriggerClick, this);
10975 this.inputEl().removeClass('x-combo-noedit');
10981 onBeforeLoad : function(combo,opts){
10982 if(!this.hasFocus){
10986 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10988 // this.restrictHeight();
10989 this.selectedIndex = -1;
10993 onLoad : function(){
10995 this.hasQuery = false;
10997 if(!this.hasFocus){
11001 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11002 this.loading.hide();
11005 if(this.store.getCount() > 0){
11007 // this.restrictHeight();
11008 if(this.lastQuery == this.allQuery){
11009 if(this.editable && !this.tickable){
11010 this.inputEl().dom.select();
11012 if(!this.selectByValue(this.value, true) && this.autoFocus){
11013 this.select(0, true);
11016 if(this.autoFocus){
11019 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11020 this.taTask.delay(this.typeAheadDelay);
11024 this.onEmptyResults();
11030 onLoadException : function()
11032 this.hasQuery = false;
11034 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11035 this.loading.hide();
11039 Roo.log(this.store.reader.jsonData);
11040 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11042 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11048 onTypeAhead : function(){
11049 if(this.store.getCount() > 0){
11050 var r = this.store.getAt(0);
11051 var newValue = r.data[this.displayField];
11052 var len = newValue.length;
11053 var selStart = this.getRawValue().length;
11055 if(selStart != len){
11056 this.setRawValue(newValue);
11057 this.selectText(selStart, newValue.length);
11063 onSelect : function(record, index){
11065 if(this.fireEvent('beforeselect', this, record, index) !== false){
11067 this.setFromData(index > -1 ? record.data : false);
11070 this.fireEvent('select', this, record, index);
11075 * Returns the currently selected field value or empty string if no value is set.
11076 * @return {String} value The selected value
11078 getValue : function(){
11081 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11084 if(this.valueField){
11085 return typeof this.value != 'undefined' ? this.value : '';
11087 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11092 * Clears any text/value currently set in the field
11094 clearValue : function(){
11095 if(this.hiddenField){
11096 this.hiddenField.dom.value = '';
11099 this.setRawValue('');
11100 this.lastSelectionText = '';
11105 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11106 * will be displayed in the field. If the value does not match the data value of an existing item,
11107 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11108 * Otherwise the field will be blank (although the value will still be set).
11109 * @param {String} value The value to match
11111 setValue : function(v){
11118 if(this.valueField){
11119 var r = this.findRecord(this.valueField, v);
11121 text = r.data[this.displayField];
11122 }else if(this.valueNotFoundText !== undefined){
11123 text = this.valueNotFoundText;
11126 this.lastSelectionText = text;
11127 if(this.hiddenField){
11128 this.hiddenField.dom.value = v;
11130 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11134 * @property {Object} the last set data for the element
11139 * Sets the value of the field based on a object which is related to the record format for the store.
11140 * @param {Object} value the value to set as. or false on reset?
11142 setFromData : function(o){
11145 if(typeof o.display_name !== 'string'){
11146 for(var i=0;i<o.display_name.length;i++){
11147 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11155 var dv = ''; // display value
11156 var vv = ''; // value value..
11158 if (this.displayField) {
11159 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11161 // this is an error condition!!!
11162 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11165 if(this.valueField){
11166 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11169 if(this.hiddenField){
11170 this.hiddenField.dom.value = vv;
11172 this.lastSelectionText = dv;
11173 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11177 // no hidden field.. - we store the value in 'value', but still display
11178 // display field!!!!
11179 this.lastSelectionText = dv;
11180 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11186 reset : function(){
11187 // overridden so that last data is reset..
11188 this.setValue(this.originalValue);
11189 this.clearInvalid();
11190 this.lastData = false;
11192 this.view.clearSelections();
11196 findRecord : function(prop, value){
11198 if(this.store.getCount() > 0){
11199 this.store.each(function(r){
11200 if(r.data[prop] == value){
11210 getName: function()
11212 // returns hidden if it's set..
11213 if (!this.rendered) {return ''};
11214 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11218 onViewMove : function(e, t){
11219 this.inKeyMode = false;
11223 onViewOver : function(e, t){
11224 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11227 var item = this.view.findItemFromChild(t);
11230 var index = this.view.indexOf(item);
11231 this.select(index, false);
11236 onViewClick : function(view, doFocus, el, e)
11238 var index = this.view.getSelectedIndexes()[0];
11240 var r = this.store.getAt(index);
11244 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11251 Roo.each(this.tickItems, function(v,k){
11253 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11254 _this.tickItems.splice(k, 1);
11264 this.tickItems.push(r.data);
11269 this.onSelect(r, index);
11271 if(doFocus !== false && !this.blockFocus){
11272 this.inputEl().focus();
11277 restrictHeight : function(){
11278 //this.innerList.dom.style.height = '';
11279 //var inner = this.innerList.dom;
11280 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11281 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11282 //this.list.beginUpdate();
11283 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11284 this.list.alignTo(this.inputEl(), this.listAlign);
11285 this.list.alignTo(this.inputEl(), this.listAlign);
11286 //this.list.endUpdate();
11290 onEmptyResults : function(){
11295 * Returns true if the dropdown list is expanded, else false.
11297 isExpanded : function(){
11298 return this.list.isVisible();
11302 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11303 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11304 * @param {String} value The data value of the item to select
11305 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11306 * selected item if it is not currently in view (defaults to true)
11307 * @return {Boolean} True if the value matched an item in the list, else false
11309 selectByValue : function(v, scrollIntoView){
11310 if(v !== undefined && v !== null){
11311 var r = this.findRecord(this.valueField || this.displayField, v);
11313 this.select(this.store.indexOf(r), scrollIntoView);
11321 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11322 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11323 * @param {Number} index The zero-based index of the list item to select
11324 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11325 * selected item if it is not currently in view (defaults to true)
11327 select : function(index, scrollIntoView){
11328 this.selectedIndex = index;
11329 this.view.select(index);
11330 if(scrollIntoView !== false){
11331 var el = this.view.getNode(index);
11332 if(el && !this.multiple && !this.tickable){
11333 this.list.scrollChildIntoView(el, false);
11339 selectNext : function(){
11340 var ct = this.store.getCount();
11342 if(this.selectedIndex == -1){
11344 }else if(this.selectedIndex < ct-1){
11345 this.select(this.selectedIndex+1);
11351 selectPrev : function(){
11352 var ct = this.store.getCount();
11354 if(this.selectedIndex == -1){
11356 }else if(this.selectedIndex != 0){
11357 this.select(this.selectedIndex-1);
11363 onKeyUp : function(e){
11364 if(this.editable !== false && !e.isSpecialKey()){
11365 this.lastKey = e.getKey();
11366 this.dqTask.delay(this.queryDelay);
11371 validateBlur : function(){
11372 return !this.list || !this.list.isVisible();
11376 initQuery : function(){
11377 this.doQuery(this.getRawValue());
11381 doForce : function(){
11382 if(this.inputEl().dom.value.length > 0){
11383 this.inputEl().dom.value =
11384 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11390 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11391 * query allowing the query action to be canceled if needed.
11392 * @param {String} query The SQL query to execute
11393 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11394 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11395 * saved in the current store (defaults to false)
11397 doQuery : function(q, forceAll){
11399 if(q === undefined || q === null){
11404 forceAll: forceAll,
11408 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11413 forceAll = qe.forceAll;
11414 if(forceAll === true || (q.length >= this.minChars)){
11416 this.hasQuery = true;
11418 if(this.lastQuery != q || this.alwaysQuery){
11419 this.lastQuery = q;
11420 if(this.mode == 'local'){
11421 this.selectedIndex = -1;
11423 this.store.clearFilter();
11425 this.store.filter(this.displayField, q);
11429 this.store.baseParams[this.queryParam] = q;
11431 var options = {params : this.getParams(q)};
11434 options.add = true;
11435 options.params.start = this.page * this.pageSize;
11438 this.store.load(options);
11440 * this code will make the page width larger, at the beginning, the list not align correctly,
11441 * we should expand the list on onLoad
11442 * so command out it
11447 this.selectedIndex = -1;
11452 this.loadNext = false;
11456 getParams : function(q){
11458 //p[this.queryParam] = q;
11462 p.limit = this.pageSize;
11468 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11470 collapse : function(){
11471 if(!this.isExpanded()){
11475 // this.hasFocus = false;
11481 this.cancelBtn.hide();
11482 this.trigger.show();
11485 Roo.get(document).un('mousedown', this.collapseIf, this);
11486 Roo.get(document).un('mousewheel', this.collapseIf, this);
11487 if (!this.editable) {
11488 Roo.get(document).un('keydown', this.listKeyPress, this);
11490 this.fireEvent('collapse', this);
11494 collapseIf : function(e){
11495 var in_combo = e.within(this.el);
11496 var in_list = e.within(this.list);
11497 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11499 if (in_combo || in_list || is_list) {
11500 //e.stopPropagation();
11505 this.onTickableFooterButtonClick(e, false, false);
11513 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11515 expand : function(){
11517 if(this.isExpanded() || !this.hasFocus){
11522 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11523 this.list.setWidth(lw);
11527 this.restrictHeight();
11531 this.tickItems = Roo.apply([], this.item);
11534 this.cancelBtn.show();
11535 this.trigger.hide();
11539 Roo.get(document).on('mousedown', this.collapseIf, this);
11540 Roo.get(document).on('mousewheel', this.collapseIf, this);
11541 if (!this.editable) {
11542 Roo.get(document).on('keydown', this.listKeyPress, this);
11545 this.fireEvent('expand', this);
11549 // Implements the default empty TriggerField.onTriggerClick function
11550 onTriggerClick : function(e)
11552 Roo.log('trigger click');
11554 if(this.disabled || !this.triggerList){
11559 this.loadNext = false;
11561 if(this.isExpanded()){
11563 if (!this.blockFocus) {
11564 this.inputEl().focus();
11568 this.hasFocus = true;
11569 if(this.triggerAction == 'all') {
11570 this.doQuery(this.allQuery, true);
11572 this.doQuery(this.getRawValue());
11574 if (!this.blockFocus) {
11575 this.inputEl().focus();
11580 onTickableTriggerClick : function(e)
11587 this.loadNext = false;
11588 this.hasFocus = true;
11590 if(this.triggerAction == 'all') {
11591 this.doQuery(this.allQuery, true);
11593 this.doQuery(this.getRawValue());
11597 onSearchFieldClick : function(e)
11599 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11604 this.loadNext = false;
11605 this.hasFocus = true;
11607 if(this.triggerAction == 'all') {
11608 this.doQuery(this.allQuery, true);
11610 this.doQuery(this.getRawValue());
11614 listKeyPress : function(e)
11616 //Roo.log('listkeypress');
11617 // scroll to first matching element based on key pres..
11618 if (e.isSpecialKey()) {
11621 var k = String.fromCharCode(e.getKey()).toUpperCase();
11624 var csel = this.view.getSelectedNodes();
11625 var cselitem = false;
11627 var ix = this.view.indexOf(csel[0]);
11628 cselitem = this.store.getAt(ix);
11629 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11635 this.store.each(function(v) {
11637 // start at existing selection.
11638 if (cselitem.id == v.id) {
11644 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11645 match = this.store.indexOf(v);
11651 if (match === false) {
11652 return true; // no more action?
11655 this.view.select(match);
11656 var sn = Roo.get(this.view.getSelectedNodes()[0])
11657 //sn.scrollIntoView(sn.dom.parentNode, false);
11660 onViewScroll : function(e, t){
11662 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11666 this.hasQuery = true;
11668 this.loading = this.list.select('.loading', true).first();
11670 if(this.loading === null){
11671 this.list.createChild({
11673 cls: 'loading select2-more-results select2-active',
11674 html: 'Loading more results...'
11677 this.loading = this.list.select('.loading', true).first();
11679 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11681 this.loading.hide();
11684 this.loading.show();
11689 this.loadNext = true;
11691 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11696 addItem : function(o)
11698 var dv = ''; // display value
11700 if (this.displayField) {
11701 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11703 // this is an error condition!!!
11704 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11711 var choice = this.choices.createChild({
11713 cls: 'select2-search-choice',
11722 cls: 'select2-search-choice-close',
11727 }, this.searchField);
11729 var close = choice.select('a.select2-search-choice-close', true).first()
11731 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11739 this.inputEl().dom.value = '';
11743 onRemoveItem : function(e, _self, o)
11745 e.preventDefault();
11746 var index = this.item.indexOf(o.data) * 1;
11749 Roo.log('not this item?!');
11753 this.item.splice(index, 1);
11758 this.fireEvent('remove', this, e);
11762 syncValue : function()
11764 if(!this.item.length){
11771 Roo.each(this.item, function(i){
11772 if(_this.valueField){
11773 value.push(i[_this.valueField]);
11780 this.value = value.join(',');
11782 if(this.hiddenField){
11783 this.hiddenField.dom.value = this.value;
11787 clearItem : function()
11789 if(!this.multiple){
11795 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11802 inputEl: function ()
11805 return this.searchField;
11807 return this.el.select('input.form-control',true).first();
11811 onTickableFooterButtonClick : function(e, btn, el)
11813 e.preventDefault();
11815 if(btn && btn.name == 'cancel'){
11816 this.tickItems = Roo.apply([], this.item);
11825 Roo.each(this.tickItems, function(o){
11836 * @cfg {Boolean} grow
11840 * @cfg {Number} growMin
11844 * @cfg {Number} growMax
11854 * Ext JS Library 1.1.1
11855 * Copyright(c) 2006-2007, Ext JS, LLC.
11857 * Originally Released Under LGPL - original licence link has changed is not relivant.
11860 * <script type="text/javascript">
11865 * @extends Roo.util.Observable
11866 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11867 * This class also supports single and multi selection modes. <br>
11868 * Create a data model bound view:
11870 var store = new Roo.data.Store(...);
11872 var view = new Roo.View({
11874 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11876 singleSelect: true,
11877 selectedClass: "ydataview-selected",
11881 // listen for node click?
11882 view.on("click", function(vw, index, node, e){
11883 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11887 dataModel.load("foobar.xml");
11889 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11891 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11892 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11894 * Note: old style constructor is still suported (container, template, config)
11897 * Create a new View
11898 * @param {Object} config The config object
11901 Roo.View = function(config, depreciated_tpl, depreciated_config){
11903 this.parent = false;
11905 if (typeof(depreciated_tpl) == 'undefined') {
11906 // new way.. - universal constructor.
11907 Roo.apply(this, config);
11908 this.el = Roo.get(this.el);
11911 this.el = Roo.get(config);
11912 this.tpl = depreciated_tpl;
11913 Roo.apply(this, depreciated_config);
11915 this.wrapEl = this.el.wrap().wrap();
11916 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11919 if(typeof(this.tpl) == "string"){
11920 this.tpl = new Roo.Template(this.tpl);
11922 // support xtype ctors..
11923 this.tpl = new Roo.factory(this.tpl, Roo);
11927 this.tpl.compile();
11932 * @event beforeclick
11933 * Fires before a click is processed. Returns false to cancel the default action.
11934 * @param {Roo.View} this
11935 * @param {Number} index The index of the target node
11936 * @param {HTMLElement} node The target node
11937 * @param {Roo.EventObject} e The raw event object
11939 "beforeclick" : true,
11942 * Fires when a template node is clicked.
11943 * @param {Roo.View} this
11944 * @param {Number} index The index of the target node
11945 * @param {HTMLElement} node The target node
11946 * @param {Roo.EventObject} e The raw event object
11951 * Fires when a template node is double clicked.
11952 * @param {Roo.View} this
11953 * @param {Number} index The index of the target node
11954 * @param {HTMLElement} node The target node
11955 * @param {Roo.EventObject} e The raw event object
11959 * @event contextmenu
11960 * Fires when a template node is right clicked.
11961 * @param {Roo.View} this
11962 * @param {Number} index The index of the target node
11963 * @param {HTMLElement} node The target node
11964 * @param {Roo.EventObject} e The raw event object
11966 "contextmenu" : true,
11968 * @event selectionchange
11969 * Fires when the selected nodes change.
11970 * @param {Roo.View} this
11971 * @param {Array} selections Array of the selected nodes
11973 "selectionchange" : true,
11976 * @event beforeselect
11977 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11978 * @param {Roo.View} this
11979 * @param {HTMLElement} node The node to be selected
11980 * @param {Array} selections Array of currently selected nodes
11982 "beforeselect" : true,
11984 * @event preparedata
11985 * Fires on every row to render, to allow you to change the data.
11986 * @param {Roo.View} this
11987 * @param {Object} data to be rendered (change this)
11989 "preparedata" : true
11997 "click": this.onClick,
11998 "dblclick": this.onDblClick,
11999 "contextmenu": this.onContextMenu,
12003 this.selections = [];
12005 this.cmp = new Roo.CompositeElementLite([]);
12007 this.store = Roo.factory(this.store, Roo.data);
12008 this.setStore(this.store, true);
12011 if ( this.footer && this.footer.xtype) {
12013 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12015 this.footer.dataSource = this.store
12016 this.footer.container = fctr;
12017 this.footer = Roo.factory(this.footer, Roo);
12018 fctr.insertFirst(this.el);
12020 // this is a bit insane - as the paging toolbar seems to detach the el..
12021 // dom.parentNode.parentNode.parentNode
12022 // they get detached?
12026 Roo.View.superclass.constructor.call(this);
12031 Roo.extend(Roo.View, Roo.util.Observable, {
12034 * @cfg {Roo.data.Store} store Data store to load data from.
12039 * @cfg {String|Roo.Element} el The container element.
12044 * @cfg {String|Roo.Template} tpl The template used by this View
12048 * @cfg {String} dataName the named area of the template to use as the data area
12049 * Works with domtemplates roo-name="name"
12053 * @cfg {String} selectedClass The css class to add to selected nodes
12055 selectedClass : "x-view-selected",
12057 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12062 * @cfg {String} text to display on mask (default Loading)
12066 * @cfg {Boolean} multiSelect Allow multiple selection
12068 multiSelect : false,
12070 * @cfg {Boolean} singleSelect Allow single selection
12072 singleSelect: false,
12075 * @cfg {Boolean} toggleSelect - selecting
12077 toggleSelect : false,
12080 * @cfg {Boolean} tickable - selecting
12085 * Returns the element this view is bound to.
12086 * @return {Roo.Element}
12088 getEl : function(){
12089 return this.wrapEl;
12095 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12097 refresh : function(){
12098 Roo.log('refresh');
12101 // if we are using something like 'domtemplate', then
12102 // the what gets used is:
12103 // t.applySubtemplate(NAME, data, wrapping data..)
12104 // the outer template then get' applied with
12105 // the store 'extra data'
12106 // and the body get's added to the
12107 // roo-name="data" node?
12108 // <span class='roo-tpl-{name}'></span> ?????
12112 this.clearSelections();
12113 this.el.update("");
12115 var records = this.store.getRange();
12116 if(records.length < 1) {
12118 // is this valid?? = should it render a template??
12120 this.el.update(this.emptyText);
12124 if (this.dataName) {
12125 this.el.update(t.apply(this.store.meta)); //????
12126 el = this.el.child('.roo-tpl-' + this.dataName);
12129 for(var i = 0, len = records.length; i < len; i++){
12130 var data = this.prepareData(records[i].data, i, records[i]);
12131 this.fireEvent("preparedata", this, data, i, records[i]);
12133 var d = Roo.apply({}, data);
12136 Roo.apply(d, {'roo-id' : Roo.id()});
12140 Roo.each(this.parent.item, function(item){
12141 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12144 Roo.apply(d, {'roo-data-checked' : 'checked'});
12148 html[html.length] = Roo.util.Format.trim(
12150 t.applySubtemplate(this.dataName, d, this.store.meta) :
12157 el.update(html.join(""));
12158 this.nodes = el.dom.childNodes;
12159 this.updateIndexes(0);
12164 * Function to override to reformat the data that is sent to
12165 * the template for each node.
12166 * DEPRICATED - use the preparedata event handler.
12167 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12168 * a JSON object for an UpdateManager bound view).
12170 prepareData : function(data, index, record)
12172 this.fireEvent("preparedata", this, data, index, record);
12176 onUpdate : function(ds, record){
12177 Roo.log('on update');
12178 this.clearSelections();
12179 var index = this.store.indexOf(record);
12180 var n = this.nodes[index];
12181 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12182 n.parentNode.removeChild(n);
12183 this.updateIndexes(index, index);
12189 onAdd : function(ds, records, index)
12191 Roo.log(['on Add', ds, records, index] );
12192 this.clearSelections();
12193 if(this.nodes.length == 0){
12197 var n = this.nodes[index];
12198 for(var i = 0, len = records.length; i < len; i++){
12199 var d = this.prepareData(records[i].data, i, records[i]);
12201 this.tpl.insertBefore(n, d);
12204 this.tpl.append(this.el, d);
12207 this.updateIndexes(index);
12210 onRemove : function(ds, record, index){
12211 Roo.log('onRemove');
12212 this.clearSelections();
12213 var el = this.dataName ?
12214 this.el.child('.roo-tpl-' + this.dataName) :
12217 el.dom.removeChild(this.nodes[index]);
12218 this.updateIndexes(index);
12222 * Refresh an individual node.
12223 * @param {Number} index
12225 refreshNode : function(index){
12226 this.onUpdate(this.store, this.store.getAt(index));
12229 updateIndexes : function(startIndex, endIndex){
12230 var ns = this.nodes;
12231 startIndex = startIndex || 0;
12232 endIndex = endIndex || ns.length - 1;
12233 for(var i = startIndex; i <= endIndex; i++){
12234 ns[i].nodeIndex = i;
12239 * Changes the data store this view uses and refresh the view.
12240 * @param {Store} store
12242 setStore : function(store, initial){
12243 if(!initial && this.store){
12244 this.store.un("datachanged", this.refresh);
12245 this.store.un("add", this.onAdd);
12246 this.store.un("remove", this.onRemove);
12247 this.store.un("update", this.onUpdate);
12248 this.store.un("clear", this.refresh);
12249 this.store.un("beforeload", this.onBeforeLoad);
12250 this.store.un("load", this.onLoad);
12251 this.store.un("loadexception", this.onLoad);
12255 store.on("datachanged", this.refresh, this);
12256 store.on("add", this.onAdd, this);
12257 store.on("remove", this.onRemove, this);
12258 store.on("update", this.onUpdate, this);
12259 store.on("clear", this.refresh, this);
12260 store.on("beforeload", this.onBeforeLoad, this);
12261 store.on("load", this.onLoad, this);
12262 store.on("loadexception", this.onLoad, this);
12270 * onbeforeLoad - masks the loading area.
12273 onBeforeLoad : function(store,opts)
12275 Roo.log('onBeforeLoad');
12277 this.el.update("");
12279 this.el.mask(this.mask ? this.mask : "Loading" );
12281 onLoad : function ()
12288 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12289 * @param {HTMLElement} node
12290 * @return {HTMLElement} The template node
12292 findItemFromChild : function(node){
12293 var el = this.dataName ?
12294 this.el.child('.roo-tpl-' + this.dataName,true) :
12297 if(!node || node.parentNode == el){
12300 var p = node.parentNode;
12301 while(p && p != el){
12302 if(p.parentNode == el){
12311 onClick : function(e){
12312 var item = this.findItemFromChild(e.getTarget());
12314 var index = this.indexOf(item);
12315 if(this.onItemClick(item, index, e) !== false){
12316 this.fireEvent("click", this, index, item, e);
12319 this.clearSelections();
12324 onContextMenu : function(e){
12325 var item = this.findItemFromChild(e.getTarget());
12327 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12332 onDblClick : function(e){
12333 var item = this.findItemFromChild(e.getTarget());
12335 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12339 onItemClick : function(item, index, e)
12341 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12344 if (this.toggleSelect) {
12345 var m = this.isSelected(item) ? 'unselect' : 'select';
12348 _t[m](item, true, false);
12351 if(this.multiSelect || this.singleSelect){
12352 if(this.multiSelect && e.shiftKey && this.lastSelection){
12353 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12355 this.select(item, this.multiSelect && e.ctrlKey);
12356 this.lastSelection = item;
12359 if(!this.tickable){
12360 e.preventDefault();
12368 * Get the number of selected nodes.
12371 getSelectionCount : function(){
12372 return this.selections.length;
12376 * Get the currently selected nodes.
12377 * @return {Array} An array of HTMLElements
12379 getSelectedNodes : function(){
12380 return this.selections;
12384 * Get the indexes of the selected nodes.
12387 getSelectedIndexes : function(){
12388 var indexes = [], s = this.selections;
12389 for(var i = 0, len = s.length; i < len; i++){
12390 indexes.push(s[i].nodeIndex);
12396 * Clear all selections
12397 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12399 clearSelections : function(suppressEvent){
12400 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12401 this.cmp.elements = this.selections;
12402 this.cmp.removeClass(this.selectedClass);
12403 this.selections = [];
12404 if(!suppressEvent){
12405 this.fireEvent("selectionchange", this, this.selections);
12411 * Returns true if the passed node is selected
12412 * @param {HTMLElement/Number} node The node or node index
12413 * @return {Boolean}
12415 isSelected : function(node){
12416 var s = this.selections;
12420 node = this.getNode(node);
12421 return s.indexOf(node) !== -1;
12426 * @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
12427 * @param {Boolean} keepExisting (optional) true to keep existing selections
12428 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12430 select : function(nodeInfo, keepExisting, suppressEvent){
12431 if(nodeInfo instanceof Array){
12433 this.clearSelections(true);
12435 for(var i = 0, len = nodeInfo.length; i < len; i++){
12436 this.select(nodeInfo[i], true, true);
12440 var node = this.getNode(nodeInfo);
12441 if(!node || this.isSelected(node)){
12442 return; // already selected.
12445 this.clearSelections(true);
12447 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12448 Roo.fly(node).addClass(this.selectedClass);
12449 this.selections.push(node);
12450 if(!suppressEvent){
12451 this.fireEvent("selectionchange", this, this.selections);
12459 * @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
12460 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12461 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12463 unselect : function(nodeInfo, keepExisting, suppressEvent)
12465 if(nodeInfo instanceof Array){
12466 Roo.each(this.selections, function(s) {
12467 this.unselect(s, nodeInfo);
12471 var node = this.getNode(nodeInfo);
12472 if(!node || !this.isSelected(node)){
12473 Roo.log("not selected");
12474 return; // not selected.
12478 Roo.each(this.selections, function(s) {
12480 Roo.fly(node).removeClass(this.selectedClass);
12487 this.selections= ns;
12488 this.fireEvent("selectionchange", this, this.selections);
12492 * Gets a template node.
12493 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12494 * @return {HTMLElement} The node or null if it wasn't found
12496 getNode : function(nodeInfo){
12497 if(typeof nodeInfo == "string"){
12498 return document.getElementById(nodeInfo);
12499 }else if(typeof nodeInfo == "number"){
12500 return this.nodes[nodeInfo];
12506 * Gets a range template nodes.
12507 * @param {Number} startIndex
12508 * @param {Number} endIndex
12509 * @return {Array} An array of nodes
12511 getNodes : function(start, end){
12512 var ns = this.nodes;
12513 start = start || 0;
12514 end = typeof end == "undefined" ? ns.length - 1 : end;
12517 for(var i = start; i <= end; i++){
12521 for(var i = start; i >= end; i--){
12529 * Finds the index of the passed node
12530 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12531 * @return {Number} The index of the node or -1
12533 indexOf : function(node){
12534 node = this.getNode(node);
12535 if(typeof node.nodeIndex == "number"){
12536 return node.nodeIndex;
12538 var ns = this.nodes;
12539 for(var i = 0, len = ns.length; i < len; i++){
12550 * based on jquery fullcalendar
12554 Roo.bootstrap = Roo.bootstrap || {};
12556 * @class Roo.bootstrap.Calendar
12557 * @extends Roo.bootstrap.Component
12558 * Bootstrap Calendar class
12559 * @cfg {Boolean} loadMask (true|false) default false
12560 * @cfg {Object} header generate the user specific header of the calendar, default false
12563 * Create a new Container
12564 * @param {Object} config The config object
12569 Roo.bootstrap.Calendar = function(config){
12570 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12574 * Fires when a date is selected
12575 * @param {DatePicker} this
12576 * @param {Date} date The selected date
12580 * @event monthchange
12581 * Fires when the displayed month changes
12582 * @param {DatePicker} this
12583 * @param {Date} date The selected month
12585 'monthchange': true,
12587 * @event evententer
12588 * Fires when mouse over an event
12589 * @param {Calendar} this
12590 * @param {event} Event
12592 'evententer': true,
12594 * @event eventleave
12595 * Fires when the mouse leaves an
12596 * @param {Calendar} this
12599 'eventleave': true,
12601 * @event eventclick
12602 * Fires when the mouse click an
12603 * @param {Calendar} this
12612 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12615 * @cfg {Number} startDay
12616 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12624 getAutoCreate : function(){
12627 var fc_button = function(name, corner, style, content ) {
12628 return Roo.apply({},{
12630 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12632 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12635 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12646 style : 'width:100%',
12653 cls : 'fc-header-left',
12655 fc_button('prev', 'left', 'arrow', '‹' ),
12656 fc_button('next', 'right', 'arrow', '›' ),
12657 { tag: 'span', cls: 'fc-header-space' },
12658 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12666 cls : 'fc-header-center',
12670 cls: 'fc-header-title',
12673 html : 'month / year'
12681 cls : 'fc-header-right',
12683 /* fc_button('month', 'left', '', 'month' ),
12684 fc_button('week', '', '', 'week' ),
12685 fc_button('day', 'right', '', 'day' )
12697 header = this.header;
12700 var cal_heads = function() {
12702 // fixme - handle this.
12704 for (var i =0; i < Date.dayNames.length; i++) {
12705 var d = Date.dayNames[i];
12708 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12709 html : d.substring(0,3)
12713 ret[0].cls += ' fc-first';
12714 ret[6].cls += ' fc-last';
12717 var cal_cell = function(n) {
12720 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12725 cls: 'fc-day-number',
12729 cls: 'fc-day-content',
12733 style: 'position: relative;' // height: 17px;
12745 var cal_rows = function() {
12748 for (var r = 0; r < 6; r++) {
12755 for (var i =0; i < Date.dayNames.length; i++) {
12756 var d = Date.dayNames[i];
12757 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12760 row.cn[0].cls+=' fc-first';
12761 row.cn[0].cn[0].style = 'min-height:90px';
12762 row.cn[6].cls+=' fc-last';
12766 ret[0].cls += ' fc-first';
12767 ret[4].cls += ' fc-prev-last';
12768 ret[5].cls += ' fc-last';
12775 cls: 'fc-border-separate',
12776 style : 'width:100%',
12784 cls : 'fc-first fc-last',
12802 cls : 'fc-content',
12803 style : "position: relative;",
12806 cls : 'fc-view fc-view-month fc-grid',
12807 style : 'position: relative',
12808 unselectable : 'on',
12811 cls : 'fc-event-container',
12812 style : 'position:absolute;z-index:8;top:0;left:0;'
12830 initEvents : function()
12833 throw "can not find store for calendar";
12839 style: "text-align:center",
12843 style: "background-color:white;width:50%;margin:250 auto",
12847 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12858 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12860 var size = this.el.select('.fc-content', true).first().getSize();
12861 this.maskEl.setSize(size.width, size.height);
12862 this.maskEl.enableDisplayMode("block");
12863 if(!this.loadMask){
12864 this.maskEl.hide();
12867 this.store = Roo.factory(this.store, Roo.data);
12868 this.store.on('load', this.onLoad, this);
12869 this.store.on('beforeload', this.onBeforeLoad, this);
12873 this.cells = this.el.select('.fc-day',true);
12874 //Roo.log(this.cells);
12875 this.textNodes = this.el.query('.fc-day-number');
12876 this.cells.addClassOnOver('fc-state-hover');
12878 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12879 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12880 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12881 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12883 this.on('monthchange', this.onMonthChange, this);
12885 this.update(new Date().clearTime());
12888 resize : function() {
12889 var sz = this.el.getSize();
12891 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12892 this.el.select('.fc-day-content div',true).setHeight(34);
12897 showPrevMonth : function(e){
12898 this.update(this.activeDate.add("mo", -1));
12900 showToday : function(e){
12901 this.update(new Date().clearTime());
12904 showNextMonth : function(e){
12905 this.update(this.activeDate.add("mo", 1));
12909 showPrevYear : function(){
12910 this.update(this.activeDate.add("y", -1));
12914 showNextYear : function(){
12915 this.update(this.activeDate.add("y", 1));
12920 update : function(date)
12922 var vd = this.activeDate;
12923 this.activeDate = date;
12924 // if(vd && this.el){
12925 // var t = date.getTime();
12926 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12927 // Roo.log('using add remove');
12929 // this.fireEvent('monthchange', this, date);
12931 // this.cells.removeClass("fc-state-highlight");
12932 // this.cells.each(function(c){
12933 // if(c.dateValue == t){
12934 // c.addClass("fc-state-highlight");
12935 // setTimeout(function(){
12936 // try{c.dom.firstChild.focus();}catch(e){}
12946 var days = date.getDaysInMonth();
12948 var firstOfMonth = date.getFirstDateOfMonth();
12949 var startingPos = firstOfMonth.getDay()-this.startDay;
12951 if(startingPos < this.startDay){
12955 var pm = date.add(Date.MONTH, -1);
12956 var prevStart = pm.getDaysInMonth()-startingPos;
12958 this.cells = this.el.select('.fc-day',true);
12959 this.textNodes = this.el.query('.fc-day-number');
12960 this.cells.addClassOnOver('fc-state-hover');
12962 var cells = this.cells.elements;
12963 var textEls = this.textNodes;
12965 Roo.each(cells, function(cell){
12966 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12969 days += startingPos;
12971 // convert everything to numbers so it's fast
12972 var day = 86400000;
12973 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12976 //Roo.log(prevStart);
12978 var today = new Date().clearTime().getTime();
12979 var sel = date.clearTime().getTime();
12980 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12981 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12982 var ddMatch = this.disabledDatesRE;
12983 var ddText = this.disabledDatesText;
12984 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12985 var ddaysText = this.disabledDaysText;
12986 var format = this.format;
12988 var setCellClass = function(cal, cell){
12992 //Roo.log('set Cell Class');
12994 var t = d.getTime();
12998 cell.dateValue = t;
13000 cell.className += " fc-today";
13001 cell.className += " fc-state-highlight";
13002 cell.title = cal.todayText;
13005 // disable highlight in other month..
13006 //cell.className += " fc-state-highlight";
13011 cell.className = " fc-state-disabled";
13012 cell.title = cal.minText;
13016 cell.className = " fc-state-disabled";
13017 cell.title = cal.maxText;
13021 if(ddays.indexOf(d.getDay()) != -1){
13022 cell.title = ddaysText;
13023 cell.className = " fc-state-disabled";
13026 if(ddMatch && format){
13027 var fvalue = d.dateFormat(format);
13028 if(ddMatch.test(fvalue)){
13029 cell.title = ddText.replace("%0", fvalue);
13030 cell.className = " fc-state-disabled";
13034 if (!cell.initialClassName) {
13035 cell.initialClassName = cell.dom.className;
13038 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13043 for(; i < startingPos; i++) {
13044 textEls[i].innerHTML = (++prevStart);
13045 d.setDate(d.getDate()+1);
13047 cells[i].className = "fc-past fc-other-month";
13048 setCellClass(this, cells[i]);
13053 for(; i < days; i++){
13054 intDay = i - startingPos + 1;
13055 textEls[i].innerHTML = (intDay);
13056 d.setDate(d.getDate()+1);
13058 cells[i].className = ''; // "x-date-active";
13059 setCellClass(this, cells[i]);
13063 for(; i < 42; i++) {
13064 textEls[i].innerHTML = (++extraDays);
13065 d.setDate(d.getDate()+1);
13067 cells[i].className = "fc-future fc-other-month";
13068 setCellClass(this, cells[i]);
13071 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13073 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13075 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13076 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13078 if(totalRows != 6){
13079 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13080 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13083 this.fireEvent('monthchange', this, date);
13087 if(!this.internalRender){
13088 var main = this.el.dom.firstChild;
13089 var w = main.offsetWidth;
13090 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13091 Roo.fly(main).setWidth(w);
13092 this.internalRender = true;
13093 // opera does not respect the auto grow header center column
13094 // then, after it gets a width opera refuses to recalculate
13095 // without a second pass
13096 if(Roo.isOpera && !this.secondPass){
13097 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13098 this.secondPass = true;
13099 this.update.defer(10, this, [date]);
13106 findCell : function(dt) {
13107 dt = dt.clearTime().getTime();
13109 this.cells.each(function(c){
13110 //Roo.log("check " +c.dateValue + '?=' + dt);
13111 if(c.dateValue == dt){
13121 findCells : function(ev) {
13122 var s = ev.start.clone().clearTime().getTime();
13124 var e= ev.end.clone().clearTime().getTime();
13127 this.cells.each(function(c){
13128 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13130 if(c.dateValue > e){
13133 if(c.dateValue < s){
13142 // findBestRow: function(cells)
13146 // for (var i =0 ; i < cells.length;i++) {
13147 // ret = Math.max(cells[i].rows || 0,ret);
13154 addItem : function(ev)
13156 // look for vertical location slot in
13157 var cells = this.findCells(ev);
13159 // ev.row = this.findBestRow(cells);
13161 // work out the location.
13165 for(var i =0; i < cells.length; i++) {
13167 cells[i].row = cells[0].row;
13170 cells[i].row = cells[i].row + 1;
13180 if (crow.start.getY() == cells[i].getY()) {
13182 crow.end = cells[i];
13199 cells[0].events.push(ev);
13201 this.calevents.push(ev);
13204 clearEvents: function() {
13206 if(!this.calevents){
13210 Roo.each(this.cells.elements, function(c){
13216 Roo.each(this.calevents, function(e) {
13217 Roo.each(e.els, function(el) {
13218 el.un('mouseenter' ,this.onEventEnter, this);
13219 el.un('mouseleave' ,this.onEventLeave, this);
13224 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13230 renderEvents: function()
13234 this.cells.each(function(c) {
13243 if(c.row != c.events.length){
13244 r = 4 - (4 - (c.row - c.events.length));
13247 c.events = ev.slice(0, r);
13248 c.more = ev.slice(r);
13250 if(c.more.length && c.more.length == 1){
13251 c.events.push(c.more.pop());
13254 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13258 this.cells.each(function(c) {
13260 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13263 for (var e = 0; e < c.events.length; e++){
13264 var ev = c.events[e];
13265 var rows = ev.rows;
13267 for(var i = 0; i < rows.length; i++) {
13269 // how many rows should it span..
13272 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13273 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13275 unselectable : "on",
13278 cls: 'fc-event-inner',
13282 // cls: 'fc-event-time',
13283 // html : cells.length > 1 ? '' : ev.time
13287 cls: 'fc-event-title',
13288 html : String.format('{0}', ev.title)
13295 cls: 'ui-resizable-handle ui-resizable-e',
13296 html : '  '
13303 cfg.cls += ' fc-event-start';
13305 if ((i+1) == rows.length) {
13306 cfg.cls += ' fc-event-end';
13309 var ctr = _this.el.select('.fc-event-container',true).first();
13310 var cg = ctr.createChild(cfg);
13312 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13313 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13315 var r = (c.more.length) ? 1 : 0;
13316 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13317 cg.setWidth(ebox.right - sbox.x -2);
13319 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13320 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13321 cg.on('click', _this.onEventClick, _this, ev);
13332 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13333 style : 'position: absolute',
13334 unselectable : "on",
13337 cls: 'fc-event-inner',
13341 cls: 'fc-event-title',
13349 cls: 'ui-resizable-handle ui-resizable-e',
13350 html : '  '
13356 var ctr = _this.el.select('.fc-event-container',true).first();
13357 var cg = ctr.createChild(cfg);
13359 var sbox = c.select('.fc-day-content',true).first().getBox();
13360 var ebox = c.select('.fc-day-content',true).first().getBox();
13362 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13363 cg.setWidth(ebox.right - sbox.x -2);
13365 cg.on('click', _this.onMoreEventClick, _this, c.more);
13375 onEventEnter: function (e, el,event,d) {
13376 this.fireEvent('evententer', this, el, event);
13379 onEventLeave: function (e, el,event,d) {
13380 this.fireEvent('eventleave', this, el, event);
13383 onEventClick: function (e, el,event,d) {
13384 this.fireEvent('eventclick', this, el, event);
13387 onMonthChange: function () {
13391 onMoreEventClick: function(e, el, more)
13395 this.calpopover.placement = 'right';
13396 this.calpopover.setTitle('More');
13398 this.calpopover.setContent('');
13400 var ctr = this.calpopover.el.select('.popover-content', true).first();
13402 Roo.each(more, function(m){
13404 cls : 'fc-event-hori fc-event-draggable',
13407 var cg = ctr.createChild(cfg);
13409 cg.on('click', _this.onEventClick, _this, m);
13412 this.calpopover.show(el);
13417 onLoad: function ()
13419 this.calevents = [];
13422 if(this.store.getCount() > 0){
13423 this.store.data.each(function(d){
13426 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13427 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13428 time : d.data.start_time,
13429 title : d.data.title,
13430 description : d.data.description,
13431 venue : d.data.venue
13436 this.renderEvents();
13438 if(this.calevents.length && this.loadMask){
13439 this.maskEl.hide();
13443 onBeforeLoad: function()
13445 this.clearEvents();
13447 this.maskEl.show();
13461 * @class Roo.bootstrap.Popover
13462 * @extends Roo.bootstrap.Component
13463 * Bootstrap Popover class
13464 * @cfg {String} html contents of the popover (or false to use children..)
13465 * @cfg {String} title of popover (or false to hide)
13466 * @cfg {String} placement how it is placed
13467 * @cfg {String} trigger click || hover (or false to trigger manually)
13468 * @cfg {String} over what (parent or false to trigger manually.)
13471 * Create a new Popover
13472 * @param {Object} config The config object
13475 Roo.bootstrap.Popover = function(config){
13476 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13479 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13481 title: 'Fill in a title',
13484 placement : 'right',
13485 trigger : 'hover', // hover
13489 can_build_overlaid : false,
13491 getChildContainer : function()
13493 return this.el.select('.popover-content',true).first();
13496 getAutoCreate : function(){
13497 Roo.log('make popover?');
13499 cls : 'popover roo-dynamic',
13500 style: 'display:block',
13506 cls : 'popover-inner',
13510 cls: 'popover-title',
13514 cls : 'popover-content',
13525 setTitle: function(str)
13527 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13529 setContent: function(str)
13531 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13533 // as it get's added to the bottom of the page.
13534 onRender : function(ct, position)
13536 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13538 var cfg = Roo.apply({}, this.getAutoCreate());
13542 cfg.cls += ' ' + this.cls;
13545 cfg.style = this.style;
13547 Roo.log("adding to ")
13548 this.el = Roo.get(document.body).createChild(cfg, position);
13554 initEvents : function()
13556 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13557 this.el.enableDisplayMode('block');
13559 if (this.over === false) {
13562 if (this.triggers === false) {
13565 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13566 var triggers = this.trigger ? this.trigger.split(' ') : [];
13567 Roo.each(triggers, function(trigger) {
13569 if (trigger == 'click') {
13570 on_el.on('click', this.toggle, this);
13571 } else if (trigger != 'manual') {
13572 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13573 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13575 on_el.on(eventIn ,this.enter, this);
13576 on_el.on(eventOut, this.leave, this);
13587 toggle : function () {
13588 this.hoverState == 'in' ? this.leave() : this.enter();
13591 enter : function () {
13594 clearTimeout(this.timeout);
13596 this.hoverState = 'in'
13598 if (!this.delay || !this.delay.show) {
13603 this.timeout = setTimeout(function () {
13604 if (_t.hoverState == 'in') {
13607 }, this.delay.show)
13609 leave : function() {
13610 clearTimeout(this.timeout);
13612 this.hoverState = 'out'
13614 if (!this.delay || !this.delay.hide) {
13619 this.timeout = setTimeout(function () {
13620 if (_t.hoverState == 'out') {
13623 }, this.delay.hide)
13626 show : function (on_el)
13629 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13632 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13633 if (this.html !== false) {
13634 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13636 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13637 if (!this.title.length) {
13638 this.el.select('.popover-title',true).hide();
13641 var placement = typeof this.placement == 'function' ?
13642 this.placement.call(this, this.el, on_el) :
13645 var autoToken = /\s?auto?\s?/i;
13646 var autoPlace = autoToken.test(placement);
13648 placement = placement.replace(autoToken, '') || 'top';
13652 //this.el.setXY([0,0]);
13654 this.el.dom.style.display='block';
13655 this.el.addClass(placement);
13657 //this.el.appendTo(on_el);
13659 var p = this.getPosition();
13660 var box = this.el.getBox();
13665 var align = Roo.bootstrap.Popover.alignment[placement]
13666 this.el.alignTo(on_el, align[0],align[1]);
13667 //var arrow = this.el.select('.arrow',true).first();
13668 //arrow.set(align[2],
13670 this.el.addClass('in');
13671 this.hoverState = null;
13673 if (this.el.hasClass('fade')) {
13680 this.el.setXY([0,0]);
13681 this.el.removeClass('in');
13688 Roo.bootstrap.Popover.alignment = {
13689 'left' : ['r-l', [-10,0], 'right'],
13690 'right' : ['l-r', [10,0], 'left'],
13691 'bottom' : ['t-b', [0,10], 'top'],
13692 'top' : [ 'b-t', [0,-10], 'bottom']
13703 * @class Roo.bootstrap.Progress
13704 * @extends Roo.bootstrap.Component
13705 * Bootstrap Progress class
13706 * @cfg {Boolean} striped striped of the progress bar
13707 * @cfg {Boolean} active animated of the progress bar
13711 * Create a new Progress
13712 * @param {Object} config The config object
13715 Roo.bootstrap.Progress = function(config){
13716 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13719 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13724 getAutoCreate : function(){
13732 cfg.cls += ' progress-striped';
13736 cfg.cls += ' active';
13755 * @class Roo.bootstrap.ProgressBar
13756 * @extends Roo.bootstrap.Component
13757 * Bootstrap ProgressBar class
13758 * @cfg {Number} aria_valuenow aria-value now
13759 * @cfg {Number} aria_valuemin aria-value min
13760 * @cfg {Number} aria_valuemax aria-value max
13761 * @cfg {String} label label for the progress bar
13762 * @cfg {String} panel (success | info | warning | danger )
13763 * @cfg {String} role role of the progress bar
13764 * @cfg {String} sr_only text
13768 * Create a new ProgressBar
13769 * @param {Object} config The config object
13772 Roo.bootstrap.ProgressBar = function(config){
13773 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13776 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13780 aria_valuemax : 100,
13786 getAutoCreate : function()
13791 cls: 'progress-bar',
13792 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13804 cfg.role = this.role;
13807 if(this.aria_valuenow){
13808 cfg['aria-valuenow'] = this.aria_valuenow;
13811 if(this.aria_valuemin){
13812 cfg['aria-valuemin'] = this.aria_valuemin;
13815 if(this.aria_valuemax){
13816 cfg['aria-valuemax'] = this.aria_valuemax;
13819 if(this.label && !this.sr_only){
13820 cfg.html = this.label;
13824 cfg.cls += ' progress-bar-' + this.panel;
13830 update : function(aria_valuenow)
13832 this.aria_valuenow = aria_valuenow;
13834 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13849 * @class Roo.bootstrap.TabGroup
13850 * @extends Roo.bootstrap.Column
13851 * Bootstrap Column class
13852 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13853 * @cfg {Boolean} carousel true to make the group behave like a carousel
13856 * Create a new TabGroup
13857 * @param {Object} config The config object
13860 Roo.bootstrap.TabGroup = function(config){
13861 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13863 this.navId = Roo.id();
13866 Roo.bootstrap.TabGroup.register(this);
13870 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13873 transition : false,
13875 getAutoCreate : function()
13877 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13879 cfg.cls += ' tab-content';
13881 if (this.carousel) {
13882 cfg.cls += ' carousel slide';
13884 cls : 'carousel-inner'
13891 getChildContainer : function()
13893 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13897 * register a Navigation item
13898 * @param {Roo.bootstrap.NavItem} the navitem to add
13900 register : function(item)
13902 this.tabs.push( item);
13903 item.navId = this.navId; // not really needed..
13907 getActivePanel : function()
13910 Roo.each(this.tabs, function(t) {
13920 getPanelByName : function(n)
13923 Roo.each(this.tabs, function(t) {
13924 if (t.tabId == n) {
13932 indexOfPanel : function(p)
13935 Roo.each(this.tabs, function(t,i) {
13936 if (t.tabId == p.tabId) {
13945 * show a specific panel
13946 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13947 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13949 showPanel : function (pan)
13952 if (typeof(pan) == 'number') {
13953 pan = this.tabs[pan];
13955 if (typeof(pan) == 'string') {
13956 pan = this.getPanelByName(pan);
13958 if (pan.tabId == this.getActivePanel().tabId) {
13961 var cur = this.getActivePanel();
13963 if (false === cur.fireEvent('beforedeactivate')) {
13967 if (this.carousel) {
13968 this.transition = true;
13969 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13970 var lr = dir == 'next' ? 'left' : 'right';
13971 pan.el.addClass(dir); // or prev
13972 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13973 cur.el.addClass(lr); // or right
13974 pan.el.addClass(lr);
13977 cur.el.on('transitionend', function() {
13978 Roo.log("trans end?");
13980 pan.el.removeClass([lr,dir]);
13981 pan.setActive(true);
13983 cur.el.removeClass([lr]);
13984 cur.setActive(false);
13986 _this.transition = false;
13988 }, this, { single: true } );
13992 cur.setActive(false);
13993 pan.setActive(true);
13997 showPanelNext : function()
13999 var i = this.indexOfPanel(this.getActivePanel());
14000 if (i > this.tabs.length) {
14003 this.showPanel(this.tabs[i+1]);
14005 showPanelPrev : function()
14007 var i = this.indexOfPanel(this.getActivePanel());
14011 this.showPanel(this.tabs[i-1]);
14022 Roo.apply(Roo.bootstrap.TabGroup, {
14026 * register a Navigation Group
14027 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14029 register : function(navgrp)
14031 this.groups[navgrp.navId] = navgrp;
14035 * fetch a Navigation Group based on the navigation ID
14036 * if one does not exist , it will get created.
14037 * @param {string} the navgroup to add
14038 * @returns {Roo.bootstrap.NavGroup} the navgroup
14040 get: function(navId) {
14041 if (typeof(this.groups[navId]) == 'undefined') {
14042 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14044 return this.groups[navId] ;
14059 * @class Roo.bootstrap.TabPanel
14060 * @extends Roo.bootstrap.Component
14061 * Bootstrap TabPanel class
14062 * @cfg {Boolean} active panel active
14063 * @cfg {String} html panel content
14064 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14065 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14069 * Create a new TabPanel
14070 * @param {Object} config The config object
14073 Roo.bootstrap.TabPanel = function(config){
14074 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14078 * Fires when the active status changes
14079 * @param {Roo.bootstrap.TabPanel} this
14080 * @param {Boolean} state the new state
14085 * @event beforedeactivate
14086 * Fires before a tab is de-activated - can be used to do validation on a form.
14087 * @param {Roo.bootstrap.TabPanel} this
14088 * @return {Boolean} false if there is an error
14091 'beforedeactivate': true
14094 this.tabId = this.tabId || Roo.id();
14098 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14105 getAutoCreate : function(){
14108 // item is needed for carousel - not sure if it has any effect otherwise
14109 cls: 'tab-pane item',
14110 html: this.html || ''
14114 cfg.cls += ' active';
14118 cfg.tabId = this.tabId;
14125 initEvents: function()
14127 Roo.log('-------- init events on tab panel ---------');
14129 var p = this.parent();
14130 this.navId = this.navId || p.navId;
14132 if (typeof(this.navId) != 'undefined') {
14133 // not really needed.. but just in case.. parent should be a NavGroup.
14134 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14135 Roo.log(['register', tg, this]);
14141 onRender : function(ct, position)
14143 // Roo.log("Call onRender: " + this.xtype);
14145 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14153 setActive: function(state)
14155 Roo.log("panel - set active " + this.tabId + "=" + state);
14157 this.active = state;
14159 this.el.removeClass('active');
14161 } else if (!this.el.hasClass('active')) {
14162 this.el.addClass('active');
14164 this.fireEvent('changed', this, state);
14181 * @class Roo.bootstrap.DateField
14182 * @extends Roo.bootstrap.Input
14183 * Bootstrap DateField class
14184 * @cfg {Number} weekStart default 0
14185 * @cfg {Number} weekStart default 0
14186 * @cfg {Number} viewMode default empty, (months|years)
14187 * @cfg {Number} minViewMode default empty, (months|years)
14188 * @cfg {Number} startDate default -Infinity
14189 * @cfg {Number} endDate default Infinity
14190 * @cfg {Boolean} todayHighlight default false
14191 * @cfg {Boolean} todayBtn default false
14192 * @cfg {Boolean} calendarWeeks default false
14193 * @cfg {Object} daysOfWeekDisabled default empty
14195 * @cfg {Boolean} keyboardNavigation default true
14196 * @cfg {String} language default en
14199 * Create a new DateField
14200 * @param {Object} config The config object
14203 Roo.bootstrap.DateField = function(config){
14204 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14208 * Fires when this field show.
14209 * @param {Roo.bootstrap.DateField} this
14210 * @param {Mixed} date The date value
14215 * Fires when this field hide.
14216 * @param {Roo.bootstrap.DateField} this
14217 * @param {Mixed} date The date value
14222 * Fires when select a date.
14223 * @param {Roo.bootstrap.DateField} this
14224 * @param {Mixed} date The date value
14230 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14233 * @cfg {String} format
14234 * The default date format string which can be overriden for localization support. The format must be
14235 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14239 * @cfg {String} altFormats
14240 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14241 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14243 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14251 todayHighlight : false,
14257 keyboardNavigation: true,
14259 calendarWeeks: false,
14261 startDate: -Infinity,
14265 daysOfWeekDisabled: [],
14269 UTCDate: function()
14271 return new Date(Date.UTC.apply(Date, arguments));
14274 UTCToday: function()
14276 var today = new Date();
14277 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14280 getDate: function() {
14281 var d = this.getUTCDate();
14282 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14285 getUTCDate: function() {
14289 setDate: function(d) {
14290 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14293 setUTCDate: function(d) {
14295 this.setValue(this.formatDate(this.date));
14298 onRender: function(ct, position)
14301 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14303 this.language = this.language || 'en';
14304 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14305 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14307 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14308 this.format = this.format || 'm/d/y';
14309 this.isInline = false;
14310 this.isInput = true;
14311 this.component = this.el.select('.add-on', true).first() || false;
14312 this.component = (this.component && this.component.length === 0) ? false : this.component;
14313 this.hasInput = this.component && this.inputEL().length;
14315 if (typeof(this.minViewMode === 'string')) {
14316 switch (this.minViewMode) {
14318 this.minViewMode = 1;
14321 this.minViewMode = 2;
14324 this.minViewMode = 0;
14329 if (typeof(this.viewMode === 'string')) {
14330 switch (this.viewMode) {
14343 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14345 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14347 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14349 this.picker().on('mousedown', this.onMousedown, this);
14350 this.picker().on('click', this.onClick, this);
14352 this.picker().addClass('datepicker-dropdown');
14354 this.startViewMode = this.viewMode;
14357 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14358 if(!this.calendarWeeks){
14363 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14364 v.attr('colspan', function(i, val){
14365 return parseInt(val) + 1;
14370 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14372 this.setStartDate(this.startDate);
14373 this.setEndDate(this.endDate);
14375 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14382 if(this.isInline) {
14387 picker : function()
14389 return this.pickerEl;
14390 // return this.el.select('.datepicker', true).first();
14393 fillDow: function()
14395 var dowCnt = this.weekStart;
14404 if(this.calendarWeeks){
14412 while (dowCnt < this.weekStart + 7) {
14416 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14420 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14423 fillMonths: function()
14426 var months = this.picker().select('>.datepicker-months td', true).first();
14428 months.dom.innerHTML = '';
14434 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14437 months.createChild(month);
14445 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14447 if (this.date < this.startDate) {
14448 this.viewDate = new Date(this.startDate);
14449 } else if (this.date > this.endDate) {
14450 this.viewDate = new Date(this.endDate);
14452 this.viewDate = new Date(this.date);
14460 var d = new Date(this.viewDate),
14461 year = d.getUTCFullYear(),
14462 month = d.getUTCMonth(),
14463 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14464 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14465 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14466 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14467 currentDate = this.date && this.date.valueOf(),
14468 today = this.UTCToday();
14470 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14472 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14474 // this.picker.select('>tfoot th.today').
14475 // .text(dates[this.language].today)
14476 // .toggle(this.todayBtn !== false);
14478 this.updateNavArrows();
14481 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14483 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14485 prevMonth.setUTCDate(day);
14487 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14489 var nextMonth = new Date(prevMonth);
14491 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14493 nextMonth = nextMonth.valueOf();
14495 var fillMonths = false;
14497 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14499 while(prevMonth.valueOf() < nextMonth) {
14502 if (prevMonth.getUTCDay() === this.weekStart) {
14504 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14512 if(this.calendarWeeks){
14513 // ISO 8601: First week contains first thursday.
14514 // ISO also states week starts on Monday, but we can be more abstract here.
14516 // Start of current week: based on weekstart/current date
14517 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14518 // Thursday of this week
14519 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14520 // First Thursday of year, year from thursday
14521 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14522 // Calendar week: ms between thursdays, div ms per day, div 7 days
14523 calWeek = (th - yth) / 864e5 / 7 + 1;
14525 fillMonths.cn.push({
14533 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14535 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14538 if (this.todayHighlight &&
14539 prevMonth.getUTCFullYear() == today.getFullYear() &&
14540 prevMonth.getUTCMonth() == today.getMonth() &&
14541 prevMonth.getUTCDate() == today.getDate()) {
14542 clsName += ' today';
14545 if (currentDate && prevMonth.valueOf() === currentDate) {
14546 clsName += ' active';
14549 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14550 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14551 clsName += ' disabled';
14554 fillMonths.cn.push({
14556 cls: 'day ' + clsName,
14557 html: prevMonth.getDate()
14560 prevMonth.setDate(prevMonth.getDate()+1);
14563 var currentYear = this.date && this.date.getUTCFullYear();
14564 var currentMonth = this.date && this.date.getUTCMonth();
14566 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14568 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14569 v.removeClass('active');
14571 if(currentYear === year && k === currentMonth){
14572 v.addClass('active');
14575 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14576 v.addClass('disabled');
14582 year = parseInt(year/10, 10) * 10;
14584 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14586 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14589 for (var i = -1; i < 11; i++) {
14590 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14592 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14600 showMode: function(dir)
14603 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14605 Roo.each(this.picker().select('>div',true).elements, function(v){
14606 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14609 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14614 if(this.isInline) return;
14616 this.picker().removeClass(['bottom', 'top']);
14618 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14620 * place to the top of element!
14624 this.picker().addClass('top');
14625 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14630 this.picker().addClass('bottom');
14632 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14635 parseDate : function(value)
14637 if(!value || value instanceof Date){
14640 var v = Date.parseDate(value, this.format);
14641 if (!v && this.useIso) {
14642 v = Date.parseDate(value, 'Y-m-d');
14644 if(!v && this.altFormats){
14645 if(!this.altFormatsArray){
14646 this.altFormatsArray = this.altFormats.split("|");
14648 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14649 v = Date.parseDate(value, this.altFormatsArray[i]);
14655 formatDate : function(date, fmt)
14657 return (!date || !(date instanceof Date)) ?
14658 date : date.dateFormat(fmt || this.format);
14661 onFocus : function()
14663 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14667 onBlur : function()
14669 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14671 var d = this.inputEl().getValue();
14682 this.picker().show();
14686 this.fireEvent('show', this, this.date);
14691 if(this.isInline) return;
14692 this.picker().hide();
14693 this.viewMode = this.startViewMode;
14696 this.fireEvent('hide', this, this.date);
14700 onMousedown: function(e)
14702 e.stopPropagation();
14703 e.preventDefault();
14708 Roo.bootstrap.DateField.superclass.keyup.call(this);
14712 setValue: function(v)
14714 var d = new Date(v);
14716 if(isNaN(d.getTime())){
14720 v = this.formatDate(d);
14722 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14724 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14728 this.fireEvent('select', this, this.date);
14732 getValue: function()
14734 return this.formatDate(this.date);
14737 fireKey: function(e)
14739 if (!this.picker().isVisible()){
14740 if (e.keyCode == 27) // allow escape to hide and re-show picker
14745 var dateChanged = false,
14747 newDate, newViewDate;
14752 e.preventDefault();
14756 if (!this.keyboardNavigation) break;
14757 dir = e.keyCode == 37 ? -1 : 1;
14760 newDate = this.moveYear(this.date, dir);
14761 newViewDate = this.moveYear(this.viewDate, dir);
14762 } else if (e.shiftKey){
14763 newDate = this.moveMonth(this.date, dir);
14764 newViewDate = this.moveMonth(this.viewDate, dir);
14766 newDate = new Date(this.date);
14767 newDate.setUTCDate(this.date.getUTCDate() + dir);
14768 newViewDate = new Date(this.viewDate);
14769 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14771 if (this.dateWithinRange(newDate)){
14772 this.date = newDate;
14773 this.viewDate = newViewDate;
14774 this.setValue(this.formatDate(this.date));
14776 e.preventDefault();
14777 dateChanged = true;
14782 if (!this.keyboardNavigation) break;
14783 dir = e.keyCode == 38 ? -1 : 1;
14785 newDate = this.moveYear(this.date, dir);
14786 newViewDate = this.moveYear(this.viewDate, dir);
14787 } else if (e.shiftKey){
14788 newDate = this.moveMonth(this.date, dir);
14789 newViewDate = this.moveMonth(this.viewDate, dir);
14791 newDate = new Date(this.date);
14792 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14793 newViewDate = new Date(this.viewDate);
14794 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14796 if (this.dateWithinRange(newDate)){
14797 this.date = newDate;
14798 this.viewDate = newViewDate;
14799 this.setValue(this.formatDate(this.date));
14801 e.preventDefault();
14802 dateChanged = true;
14806 this.setValue(this.formatDate(this.date));
14808 e.preventDefault();
14811 this.setValue(this.formatDate(this.date));
14825 onClick: function(e)
14827 e.stopPropagation();
14828 e.preventDefault();
14830 var target = e.getTarget();
14832 if(target.nodeName.toLowerCase() === 'i'){
14833 target = Roo.get(target).dom.parentNode;
14836 var nodeName = target.nodeName;
14837 var className = target.className;
14838 var html = target.innerHTML;
14840 switch(nodeName.toLowerCase()) {
14842 switch(className) {
14848 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14849 switch(this.viewMode){
14851 this.viewDate = this.moveMonth(this.viewDate, dir);
14855 this.viewDate = this.moveYear(this.viewDate, dir);
14861 var date = new Date();
14862 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14864 this.setValue(this.formatDate(this.date));
14871 if (className.indexOf('disabled') === -1) {
14872 this.viewDate.setUTCDate(1);
14873 if (className.indexOf('month') !== -1) {
14874 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14876 var year = parseInt(html, 10) || 0;
14877 this.viewDate.setUTCFullYear(year);
14886 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14887 var day = parseInt(html, 10) || 1;
14888 var year = this.viewDate.getUTCFullYear(),
14889 month = this.viewDate.getUTCMonth();
14891 if (className.indexOf('old') !== -1) {
14898 } else if (className.indexOf('new') !== -1) {
14906 this.date = this.UTCDate(year, month, day,0,0,0,0);
14907 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14909 this.setValue(this.formatDate(this.date));
14916 setStartDate: function(startDate)
14918 this.startDate = startDate || -Infinity;
14919 if (this.startDate !== -Infinity) {
14920 this.startDate = this.parseDate(this.startDate);
14923 this.updateNavArrows();
14926 setEndDate: function(endDate)
14928 this.endDate = endDate || Infinity;
14929 if (this.endDate !== Infinity) {
14930 this.endDate = this.parseDate(this.endDate);
14933 this.updateNavArrows();
14936 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14938 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14939 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14940 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14942 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14943 return parseInt(d, 10);
14946 this.updateNavArrows();
14949 updateNavArrows: function()
14951 var d = new Date(this.viewDate),
14952 year = d.getUTCFullYear(),
14953 month = d.getUTCMonth();
14955 Roo.each(this.picker().select('.prev', true).elements, function(v){
14957 switch (this.viewMode) {
14960 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14966 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14973 Roo.each(this.picker().select('.next', true).elements, function(v){
14975 switch (this.viewMode) {
14978 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14984 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14992 moveMonth: function(date, dir)
14994 if (!dir) return date;
14995 var new_date = new Date(date.valueOf()),
14996 day = new_date.getUTCDate(),
14997 month = new_date.getUTCMonth(),
14998 mag = Math.abs(dir),
15000 dir = dir > 0 ? 1 : -1;
15003 // If going back one month, make sure month is not current month
15004 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15006 return new_date.getUTCMonth() == month;
15008 // If going forward one month, make sure month is as expected
15009 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15011 return new_date.getUTCMonth() != new_month;
15013 new_month = month + dir;
15014 new_date.setUTCMonth(new_month);
15015 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15016 if (new_month < 0 || new_month > 11)
15017 new_month = (new_month + 12) % 12;
15019 // For magnitudes >1, move one month at a time...
15020 for (var i=0; i<mag; i++)
15021 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15022 new_date = this.moveMonth(new_date, dir);
15023 // ...then reset the day, keeping it in the new month
15024 new_month = new_date.getUTCMonth();
15025 new_date.setUTCDate(day);
15027 return new_month != new_date.getUTCMonth();
15030 // Common date-resetting loop -- if date is beyond end of month, make it
15033 new_date.setUTCDate(--day);
15034 new_date.setUTCMonth(new_month);
15039 moveYear: function(date, dir)
15041 return this.moveMonth(date, dir*12);
15044 dateWithinRange: function(date)
15046 return date >= this.startDate && date <= this.endDate;
15052 this.picker().remove();
15057 Roo.apply(Roo.bootstrap.DateField, {
15068 html: '<i class="fa fa-arrow-left"/>'
15078 html: '<i class="fa fa-arrow-right"/>'
15120 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15121 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15122 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15123 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15124 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15137 navFnc: 'FullYear',
15142 navFnc: 'FullYear',
15147 Roo.apply(Roo.bootstrap.DateField, {
15151 cls: 'datepicker dropdown-menu',
15155 cls: 'datepicker-days',
15159 cls: 'table-condensed',
15161 Roo.bootstrap.DateField.head,
15165 Roo.bootstrap.DateField.footer
15172 cls: 'datepicker-months',
15176 cls: 'table-condensed',
15178 Roo.bootstrap.DateField.head,
15179 Roo.bootstrap.DateField.content,
15180 Roo.bootstrap.DateField.footer
15187 cls: 'datepicker-years',
15191 cls: 'table-condensed',
15193 Roo.bootstrap.DateField.head,
15194 Roo.bootstrap.DateField.content,
15195 Roo.bootstrap.DateField.footer
15214 * @class Roo.bootstrap.TimeField
15215 * @extends Roo.bootstrap.Input
15216 * Bootstrap DateField class
15220 * Create a new TimeField
15221 * @param {Object} config The config object
15224 Roo.bootstrap.TimeField = function(config){
15225 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15229 * Fires when this field show.
15230 * @param {Roo.bootstrap.DateField} this
15231 * @param {Mixed} date The date value
15236 * Fires when this field hide.
15237 * @param {Roo.bootstrap.DateField} this
15238 * @param {Mixed} date The date value
15243 * Fires when select a date.
15244 * @param {Roo.bootstrap.DateField} this
15245 * @param {Mixed} date The date value
15251 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15254 * @cfg {String} format
15255 * The default time format string which can be overriden for localization support. The format must be
15256 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15260 onRender: function(ct, position)
15263 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15265 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15267 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15269 this.pop = this.picker().select('>.datepicker-time',true).first();
15270 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15272 this.picker().on('mousedown', this.onMousedown, this);
15273 this.picker().on('click', this.onClick, this);
15275 this.picker().addClass('datepicker-dropdown');
15280 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15281 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15282 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15283 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15284 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15285 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15289 fireKey: function(e){
15290 if (!this.picker().isVisible()){
15291 if (e.keyCode == 27) // allow escape to hide and re-show picker
15296 e.preventDefault();
15304 this.onTogglePeriod();
15307 this.onIncrementMinutes();
15310 this.onDecrementMinutes();
15319 onClick: function(e) {
15320 e.stopPropagation();
15321 e.preventDefault();
15324 picker : function()
15326 return this.el.select('.datepicker', true).first();
15329 fillTime: function()
15331 var time = this.pop.select('tbody', true).first();
15333 time.dom.innerHTML = '';
15348 cls: 'hours-up glyphicon glyphicon-chevron-up'
15368 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15389 cls: 'timepicker-hour',
15404 cls: 'timepicker-minute',
15419 cls: 'btn btn-primary period',
15441 cls: 'hours-down glyphicon glyphicon-chevron-down'
15461 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15479 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15486 var hours = this.time.getHours();
15487 var minutes = this.time.getMinutes();
15500 hours = hours - 12;
15504 hours = '0' + hours;
15508 minutes = '0' + minutes;
15511 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15512 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15513 this.pop.select('button', true).first().dom.innerHTML = period;
15519 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15521 var cls = ['bottom'];
15523 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15530 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15535 this.picker().addClass(cls.join('-'));
15539 Roo.each(cls, function(c){
15541 _this.picker().setTop(_this.inputEl().getHeight());
15545 _this.picker().setTop(0 - _this.picker().getHeight());
15550 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15554 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15561 onFocus : function()
15563 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15567 onBlur : function()
15569 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15575 this.picker().show();
15580 this.fireEvent('show', this, this.date);
15585 this.picker().hide();
15588 this.fireEvent('hide', this, this.date);
15591 setTime : function()
15594 this.setValue(this.time.format(this.format));
15596 this.fireEvent('select', this, this.date);
15601 onMousedown: function(e){
15602 e.stopPropagation();
15603 e.preventDefault();
15606 onIncrementHours: function()
15608 Roo.log('onIncrementHours');
15609 this.time = this.time.add(Date.HOUR, 1);
15614 onDecrementHours: function()
15616 Roo.log('onDecrementHours');
15617 this.time = this.time.add(Date.HOUR, -1);
15621 onIncrementMinutes: function()
15623 Roo.log('onIncrementMinutes');
15624 this.time = this.time.add(Date.MINUTE, 1);
15628 onDecrementMinutes: function()
15630 Roo.log('onDecrementMinutes');
15631 this.time = this.time.add(Date.MINUTE, -1);
15635 onTogglePeriod: function()
15637 Roo.log('onTogglePeriod');
15638 this.time = this.time.add(Date.HOUR, 12);
15645 Roo.apply(Roo.bootstrap.TimeField, {
15675 cls: 'btn btn-info ok',
15687 Roo.apply(Roo.bootstrap.TimeField, {
15691 cls: 'datepicker dropdown-menu',
15695 cls: 'datepicker-time',
15699 cls: 'table-condensed',
15701 Roo.bootstrap.TimeField.content,
15702 Roo.bootstrap.TimeField.footer
15721 * @class Roo.bootstrap.CheckBox
15722 * @extends Roo.bootstrap.Input
15723 * Bootstrap CheckBox class
15725 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15726 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15727 * @cfg {String} boxLabel The text that appears beside the checkbox
15728 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15729 * @cfg {Boolean} checked initnal the element
15733 * Create a new CheckBox
15734 * @param {Object} config The config object
15737 Roo.bootstrap.CheckBox = function(config){
15738 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15743 * Fires when the element is checked or unchecked.
15744 * @param {Roo.bootstrap.CheckBox} this This input
15745 * @param {Boolean} checked The new checked value
15751 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15753 inputType: 'checkbox',
15760 getAutoCreate : function()
15762 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15768 cfg.cls = 'form-group checkbox' //input-group
15776 type : this.inputType,
15777 value : (!this.checked) ? this.valueOff : this.inputValue,
15778 cls : 'roo-checkbox', //'form-box',
15779 placeholder : this.placeholder || ''
15783 if (this.weight) { // Validity check?
15784 cfg.cls += " checkbox-" + this.weight;
15787 if (this.disabled) {
15788 input.disabled=true;
15792 input.checked = this.checked;
15796 input.name = this.name;
15800 input.cls += ' input-' + this.size;
15804 ['xs','sm','md','lg'].map(function(size){
15805 if (settings[size]) {
15806 cfg.cls += ' col-' + size + '-' + settings[size];
15812 var inputblock = input;
15817 if (this.before || this.after) {
15820 cls : 'input-group',
15824 inputblock.cn.push({
15826 cls : 'input-group-addon',
15830 inputblock.cn.push(input);
15832 inputblock.cn.push({
15834 cls : 'input-group-addon',
15841 if (align ==='left' && this.fieldLabel.length) {
15842 Roo.log("left and has label");
15848 cls : 'control-label col-md-' + this.labelWidth,
15849 html : this.fieldLabel
15853 cls : "col-md-" + (12 - this.labelWidth),
15860 } else if ( this.fieldLabel.length) {
15865 tag: this.boxLabel ? 'span' : 'label',
15867 cls: 'control-label box-input-label',
15868 //cls : 'input-group-addon',
15869 html : this.fieldLabel
15879 Roo.log(" no label && no align");
15880 cfg.cn = [ inputblock ] ;
15889 html: this.boxLabel
15901 * return the real input element.
15903 inputEl: function ()
15905 return this.el.select('input.roo-checkbox',true).first();
15910 return this.el.select('label.control-label',true).first();
15913 initEvents : function()
15915 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15917 this.inputEl().on('click', this.onClick, this);
15921 onClick : function()
15923 this.setChecked(!this.checked);
15926 setChecked : function(state,suppressEvent)
15928 this.checked = state;
15930 this.inputEl().dom.checked = state;
15932 if(suppressEvent !== true){
15933 this.fireEvent('check', this, state);
15936 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15940 setValue : function(v,suppressEvent)
15942 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15956 * @class Roo.bootstrap.Radio
15957 * @extends Roo.bootstrap.CheckBox
15958 * Bootstrap Radio class
15961 * Create a new Radio
15962 * @param {Object} config The config object
15965 Roo.bootstrap.Radio = function(config){
15966 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15970 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15972 inputType: 'radio',
15976 getAutoCreate : function()
15978 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15984 cfg.cls = 'form-group radio' //input-group
15989 type : this.inputType,
15990 value : (!this.checked) ? this.valueOff : this.inputValue,
15992 placeholder : this.placeholder || ''
15995 if (this.weight) { // Validity check?
15996 cfg.cls += " radio-" + this.weight;
15998 if (this.disabled) {
15999 input.disabled=true;
16003 input.checked = this.checked;
16007 input.name = this.name;
16011 input.cls += ' input-' + this.size;
16015 ['xs','sm','md','lg'].map(function(size){
16016 if (settings[size]) {
16017 cfg.cls += ' col-' + size + '-' + settings[size];
16021 var inputblock = input;
16023 if (this.before || this.after) {
16026 cls : 'input-group',
16030 inputblock.cn.push({
16032 cls : 'input-group-addon',
16036 inputblock.cn.push(input);
16038 inputblock.cn.push({
16040 cls : 'input-group-addon',
16047 if (align ==='left' && this.fieldLabel.length) {
16048 Roo.log("left and has label");
16054 cls : 'control-label col-md-' + this.labelWidth,
16055 html : this.fieldLabel
16059 cls : "col-md-" + (12 - this.labelWidth),
16066 } else if ( this.fieldLabel.length) {
16073 cls: 'control-label box-input-label',
16074 //cls : 'input-group-addon',
16075 html : this.fieldLabel
16085 Roo.log(" no label && no align");
16100 html: this.boxLabel
16107 inputEl: function ()
16109 return this.el.select('input.roo-radio',true).first();
16111 onClick : function()
16113 this.setChecked(true);
16116 setChecked : function(state,suppressEvent)
16119 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16120 v.dom.checked = false;
16124 this.checked = state;
16125 this.inputEl().dom.checked = state;
16127 if(suppressEvent !== true){
16128 this.fireEvent('check', this, state);
16131 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16135 getGroupValue : function()
16138 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16139 if(v.dom.checked == true){
16140 value = v.dom.value;
16148 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16149 * @return {Mixed} value The field value
16151 getValue : function(){
16152 return this.getGroupValue();
16158 //<script type="text/javascript">
16161 * Based Ext JS Library 1.1.1
16162 * Copyright(c) 2006-2007, Ext JS, LLC.
16168 * @class Roo.HtmlEditorCore
16169 * @extends Roo.Component
16170 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16172 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16175 Roo.HtmlEditorCore = function(config){
16178 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16181 * @event initialize
16182 * Fires when the editor is fully initialized (including the iframe)
16183 * @param {Roo.HtmlEditorCore} this
16188 * Fires when the editor is first receives the focus. Any insertion must wait
16189 * until after this event.
16190 * @param {Roo.HtmlEditorCore} this
16194 * @event beforesync
16195 * Fires before the textarea is updated with content from the editor iframe. Return false
16196 * to cancel the sync.
16197 * @param {Roo.HtmlEditorCore} this
16198 * @param {String} html
16202 * @event beforepush
16203 * Fires before the iframe editor is updated with content from the textarea. Return false
16204 * to cancel the push.
16205 * @param {Roo.HtmlEditorCore} this
16206 * @param {String} html
16211 * Fires when the textarea is updated with content from the editor iframe.
16212 * @param {Roo.HtmlEditorCore} this
16213 * @param {String} html
16218 * Fires when the iframe editor is updated with content from the textarea.
16219 * @param {Roo.HtmlEditorCore} this
16220 * @param {String} html
16225 * @event editorevent
16226 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16227 * @param {Roo.HtmlEditorCore} this
16235 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16239 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16245 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16250 * @cfg {Number} height (in pixels)
16254 * @cfg {Number} width (in pixels)
16259 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16262 stylesheets: false,
16267 // private properties
16268 validationEvent : false,
16270 initialized : false,
16272 sourceEditMode : false,
16273 onFocus : Roo.emptyFn,
16275 hideMode:'offsets',
16283 * Protected method that will not generally be called directly. It
16284 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16285 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16287 getDocMarkup : function(){
16290 Roo.log(this.stylesheets);
16292 // inherit styels from page...??
16293 if (this.stylesheets === false) {
16295 Roo.get(document.head).select('style').each(function(node) {
16296 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16299 Roo.get(document.head).select('link').each(function(node) {
16300 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16303 } else if (!this.stylesheets.length) {
16305 st = '<style type="text/css">' +
16306 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16309 Roo.each(this.stylesheets, function(s) {
16310 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16315 st += '<style type="text/css">' +
16316 'IMG { cursor: pointer } ' +
16320 return '<html><head>' + st +
16321 //<style type="text/css">' +
16322 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16324 ' </head><body class="roo-htmleditor-body"></body></html>';
16328 onRender : function(ct, position)
16331 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16332 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16335 this.el.dom.style.border = '0 none';
16336 this.el.dom.setAttribute('tabIndex', -1);
16337 this.el.addClass('x-hidden hide');
16341 if(Roo.isIE){ // fix IE 1px bogus margin
16342 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16346 this.frameId = Roo.id();
16350 var iframe = this.owner.wrap.createChild({
16352 cls: 'form-control', // bootstrap..
16354 name: this.frameId,
16355 frameBorder : 'no',
16356 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16361 this.iframe = iframe.dom;
16363 this.assignDocWin();
16365 this.doc.designMode = 'on';
16368 this.doc.write(this.getDocMarkup());
16372 var task = { // must defer to wait for browser to be ready
16374 //console.log("run task?" + this.doc.readyState);
16375 this.assignDocWin();
16376 if(this.doc.body || this.doc.readyState == 'complete'){
16378 this.doc.designMode="on";
16382 Roo.TaskMgr.stop(task);
16383 this.initEditor.defer(10, this);
16390 Roo.TaskMgr.start(task);
16397 onResize : function(w, h)
16399 Roo.log('resize: ' +w + ',' + h );
16400 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16404 if(typeof w == 'number'){
16406 this.iframe.style.width = w + 'px';
16408 if(typeof h == 'number'){
16410 this.iframe.style.height = h + 'px';
16412 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16419 * Toggles the editor between standard and source edit mode.
16420 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16422 toggleSourceEdit : function(sourceEditMode){
16424 this.sourceEditMode = sourceEditMode === true;
16426 if(this.sourceEditMode){
16428 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16431 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16432 //this.iframe.className = '';
16435 //this.setSize(this.owner.wrap.getSize());
16436 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16443 * Protected method that will not generally be called directly. If you need/want
16444 * custom HTML cleanup, this is the method you should override.
16445 * @param {String} html The HTML to be cleaned
16446 * return {String} The cleaned HTML
16448 cleanHtml : function(html){
16449 html = String(html);
16450 if(html.length > 5){
16451 if(Roo.isSafari){ // strip safari nonsense
16452 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16455 if(html == ' '){
16462 * HTML Editor -> Textarea
16463 * Protected method that will not generally be called directly. Syncs the contents
16464 * of the editor iframe with the textarea.
16466 syncValue : function(){
16467 if(this.initialized){
16468 var bd = (this.doc.body || this.doc.documentElement);
16469 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16470 var html = bd.innerHTML;
16472 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16473 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16475 html = '<div style="'+m[0]+'">' + html + '</div>';
16478 html = this.cleanHtml(html);
16479 // fix up the special chars.. normaly like back quotes in word...
16480 // however we do not want to do this with chinese..
16481 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16482 var cc = b.charCodeAt();
16484 (cc >= 0x4E00 && cc < 0xA000 ) ||
16485 (cc >= 0x3400 && cc < 0x4E00 ) ||
16486 (cc >= 0xf900 && cc < 0xfb00 )
16492 if(this.owner.fireEvent('beforesync', this, html) !== false){
16493 this.el.dom.value = html;
16494 this.owner.fireEvent('sync', this, html);
16500 * Protected method that will not generally be called directly. Pushes the value of the textarea
16501 * into the iframe editor.
16503 pushValue : function(){
16504 if(this.initialized){
16505 var v = this.el.dom.value.trim();
16507 // if(v.length < 1){
16511 if(this.owner.fireEvent('beforepush', this, v) !== false){
16512 var d = (this.doc.body || this.doc.documentElement);
16514 this.cleanUpPaste();
16515 this.el.dom.value = d.innerHTML;
16516 this.owner.fireEvent('push', this, v);
16522 deferFocus : function(){
16523 this.focus.defer(10, this);
16527 focus : function(){
16528 if(this.win && !this.sourceEditMode){
16535 assignDocWin: function()
16537 var iframe = this.iframe;
16540 this.doc = iframe.contentWindow.document;
16541 this.win = iframe.contentWindow;
16543 // if (!Roo.get(this.frameId)) {
16546 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16547 // this.win = Roo.get(this.frameId).dom.contentWindow;
16549 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16553 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16554 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16559 initEditor : function(){
16560 //console.log("INIT EDITOR");
16561 this.assignDocWin();
16565 this.doc.designMode="on";
16567 this.doc.write(this.getDocMarkup());
16570 var dbody = (this.doc.body || this.doc.documentElement);
16571 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16572 // this copies styles from the containing element into thsi one..
16573 // not sure why we need all of this..
16574 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16576 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16577 //ss['background-attachment'] = 'fixed'; // w3c
16578 dbody.bgProperties = 'fixed'; // ie
16579 //Roo.DomHelper.applyStyles(dbody, ss);
16580 Roo.EventManager.on(this.doc, {
16581 //'mousedown': this.onEditorEvent,
16582 'mouseup': this.onEditorEvent,
16583 'dblclick': this.onEditorEvent,
16584 'click': this.onEditorEvent,
16585 'keyup': this.onEditorEvent,
16590 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16592 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16593 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16595 this.initialized = true;
16597 this.owner.fireEvent('initialize', this);
16602 onDestroy : function(){
16608 //for (var i =0; i < this.toolbars.length;i++) {
16609 // // fixme - ask toolbars for heights?
16610 // this.toolbars[i].onDestroy();
16613 //this.wrap.dom.innerHTML = '';
16614 //this.wrap.remove();
16619 onFirstFocus : function(){
16621 this.assignDocWin();
16624 this.activated = true;
16627 if(Roo.isGecko){ // prevent silly gecko errors
16629 var s = this.win.getSelection();
16630 if(!s.focusNode || s.focusNode.nodeType != 3){
16631 var r = s.getRangeAt(0);
16632 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16637 this.execCmd('useCSS', true);
16638 this.execCmd('styleWithCSS', false);
16641 this.owner.fireEvent('activate', this);
16645 adjustFont: function(btn){
16646 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16647 //if(Roo.isSafari){ // safari
16650 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16651 if(Roo.isSafari){ // safari
16652 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16653 v = (v < 10) ? 10 : v;
16654 v = (v > 48) ? 48 : v;
16655 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16660 v = Math.max(1, v+adjust);
16662 this.execCmd('FontSize', v );
16665 onEditorEvent : function(e){
16666 this.owner.fireEvent('editorevent', this, e);
16667 // this.updateToolbar();
16668 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16671 insertTag : function(tg)
16673 // could be a bit smarter... -> wrap the current selected tRoo..
16674 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16676 range = this.createRange(this.getSelection());
16677 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16678 wrappingNode.appendChild(range.extractContents());
16679 range.insertNode(wrappingNode);
16686 this.execCmd("formatblock", tg);
16690 insertText : function(txt)
16694 var range = this.createRange();
16695 range.deleteContents();
16696 //alert(Sender.getAttribute('label'));
16698 range.insertNode(this.doc.createTextNode(txt));
16704 * Executes a Midas editor command on the editor document and performs necessary focus and
16705 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16706 * @param {String} cmd The Midas command
16707 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16709 relayCmd : function(cmd, value){
16711 this.execCmd(cmd, value);
16712 this.owner.fireEvent('editorevent', this);
16713 //this.updateToolbar();
16714 this.owner.deferFocus();
16718 * Executes a Midas editor command directly on the editor document.
16719 * For visual commands, you should use {@link #relayCmd} instead.
16720 * <b>This should only be called after the editor is initialized.</b>
16721 * @param {String} cmd The Midas command
16722 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16724 execCmd : function(cmd, value){
16725 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16732 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16734 * @param {String} text | dom node..
16736 insertAtCursor : function(text)
16741 if(!this.activated){
16747 var r = this.doc.selection.createRange();
16758 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16762 // from jquery ui (MIT licenced)
16764 var win = this.win;
16766 if (win.getSelection && win.getSelection().getRangeAt) {
16767 range = win.getSelection().getRangeAt(0);
16768 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16769 range.insertNode(node);
16770 } else if (win.document.selection && win.document.selection.createRange) {
16771 // no firefox support
16772 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16773 win.document.selection.createRange().pasteHTML(txt);
16775 // no firefox support
16776 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16777 this.execCmd('InsertHTML', txt);
16786 mozKeyPress : function(e){
16788 var c = e.getCharCode(), cmd;
16791 c = String.fromCharCode(c).toLowerCase();
16805 this.cleanUpPaste.defer(100, this);
16813 e.preventDefault();
16821 fixKeys : function(){ // load time branching for fastest keydown performance
16823 return function(e){
16824 var k = e.getKey(), r;
16827 r = this.doc.selection.createRange();
16830 r.pasteHTML('    ');
16837 r = this.doc.selection.createRange();
16839 var target = r.parentElement();
16840 if(!target || target.tagName.toLowerCase() != 'li'){
16842 r.pasteHTML('<br />');
16848 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16849 this.cleanUpPaste.defer(100, this);
16855 }else if(Roo.isOpera){
16856 return function(e){
16857 var k = e.getKey();
16861 this.execCmd('InsertHTML','    ');
16864 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16865 this.cleanUpPaste.defer(100, this);
16870 }else if(Roo.isSafari){
16871 return function(e){
16872 var k = e.getKey();
16876 this.execCmd('InsertText','\t');
16880 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16881 this.cleanUpPaste.defer(100, this);
16889 getAllAncestors: function()
16891 var p = this.getSelectedNode();
16894 a.push(p); // push blank onto stack..
16895 p = this.getParentElement();
16899 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16903 a.push(this.doc.body);
16907 lastSelNode : false,
16910 getSelection : function()
16912 this.assignDocWin();
16913 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16916 getSelectedNode: function()
16918 // this may only work on Gecko!!!
16920 // should we cache this!!!!
16925 var range = this.createRange(this.getSelection()).cloneRange();
16928 var parent = range.parentElement();
16930 var testRange = range.duplicate();
16931 testRange.moveToElementText(parent);
16932 if (testRange.inRange(range)) {
16935 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16938 parent = parent.parentElement;
16943 // is ancestor a text element.
16944 var ac = range.commonAncestorContainer;
16945 if (ac.nodeType == 3) {
16946 ac = ac.parentNode;
16949 var ar = ac.childNodes;
16952 var other_nodes = [];
16953 var has_other_nodes = false;
16954 for (var i=0;i<ar.length;i++) {
16955 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16958 // fullly contained node.
16960 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16965 // probably selected..
16966 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16967 other_nodes.push(ar[i]);
16971 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16976 has_other_nodes = true;
16978 if (!nodes.length && other_nodes.length) {
16979 nodes= other_nodes;
16981 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16987 createRange: function(sel)
16989 // this has strange effects when using with
16990 // top toolbar - not sure if it's a great idea.
16991 //this.editor.contentWindow.focus();
16992 if (typeof sel != "undefined") {
16994 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16996 return this.doc.createRange();
16999 return this.doc.createRange();
17002 getParentElement: function()
17005 this.assignDocWin();
17006 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17008 var range = this.createRange(sel);
17011 var p = range.commonAncestorContainer;
17012 while (p.nodeType == 3) { // text node
17023 * Range intersection.. the hard stuff...
17027 * [ -- selected range --- ]
17031 * if end is before start or hits it. fail.
17032 * if start is after end or hits it fail.
17034 * if either hits (but other is outside. - then it's not
17040 // @see http://www.thismuchiknow.co.uk/?p=64.
17041 rangeIntersectsNode : function(range, node)
17043 var nodeRange = node.ownerDocument.createRange();
17045 nodeRange.selectNode(node);
17047 nodeRange.selectNodeContents(node);
17050 var rangeStartRange = range.cloneRange();
17051 rangeStartRange.collapse(true);
17053 var rangeEndRange = range.cloneRange();
17054 rangeEndRange.collapse(false);
17056 var nodeStartRange = nodeRange.cloneRange();
17057 nodeStartRange.collapse(true);
17059 var nodeEndRange = nodeRange.cloneRange();
17060 nodeEndRange.collapse(false);
17062 return rangeStartRange.compareBoundaryPoints(
17063 Range.START_TO_START, nodeEndRange) == -1 &&
17064 rangeEndRange.compareBoundaryPoints(
17065 Range.START_TO_START, nodeStartRange) == 1;
17069 rangeCompareNode : function(range, node)
17071 var nodeRange = node.ownerDocument.createRange();
17073 nodeRange.selectNode(node);
17075 nodeRange.selectNodeContents(node);
17079 range.collapse(true);
17081 nodeRange.collapse(true);
17083 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17084 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17086 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17088 var nodeIsBefore = ss == 1;
17089 var nodeIsAfter = ee == -1;
17091 if (nodeIsBefore && nodeIsAfter)
17093 if (!nodeIsBefore && nodeIsAfter)
17094 return 1; //right trailed.
17096 if (nodeIsBefore && !nodeIsAfter)
17097 return 2; // left trailed.
17102 // private? - in a new class?
17103 cleanUpPaste : function()
17105 // cleans up the whole document..
17106 Roo.log('cleanuppaste');
17108 this.cleanUpChildren(this.doc.body);
17109 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17110 if (clean != this.doc.body.innerHTML) {
17111 this.doc.body.innerHTML = clean;
17116 cleanWordChars : function(input) {// change the chars to hex code
17117 var he = Roo.HtmlEditorCore;
17119 var output = input;
17120 Roo.each(he.swapCodes, function(sw) {
17121 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17123 output = output.replace(swapper, sw[1]);
17130 cleanUpChildren : function (n)
17132 if (!n.childNodes.length) {
17135 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17136 this.cleanUpChild(n.childNodes[i]);
17143 cleanUpChild : function (node)
17146 //console.log(node);
17147 if (node.nodeName == "#text") {
17148 // clean up silly Windows -- stuff?
17151 if (node.nodeName == "#comment") {
17152 node.parentNode.removeChild(node);
17153 // clean up silly Windows -- stuff?
17157 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17159 node.parentNode.removeChild(node);
17164 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17166 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17167 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17169 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17170 // remove_keep_children = true;
17173 if (remove_keep_children) {
17174 this.cleanUpChildren(node);
17175 // inserts everything just before this node...
17176 while (node.childNodes.length) {
17177 var cn = node.childNodes[0];
17178 node.removeChild(cn);
17179 node.parentNode.insertBefore(cn, node);
17181 node.parentNode.removeChild(node);
17185 if (!node.attributes || !node.attributes.length) {
17186 this.cleanUpChildren(node);
17190 function cleanAttr(n,v)
17193 if (v.match(/^\./) || v.match(/^\//)) {
17196 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17199 if (v.match(/^#/)) {
17202 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17203 node.removeAttribute(n);
17207 function cleanStyle(n,v)
17209 if (v.match(/expression/)) { //XSS?? should we even bother..
17210 node.removeAttribute(n);
17213 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17214 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17217 var parts = v.split(/;/);
17220 Roo.each(parts, function(p) {
17221 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17225 var l = p.split(':').shift().replace(/\s+/g,'');
17226 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17228 if ( cblack.indexOf(l) > -1) {
17229 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17230 //node.removeAttribute(n);
17234 // only allow 'c whitelisted system attributes'
17235 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17236 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17237 //node.removeAttribute(n);
17247 if (clean.length) {
17248 node.setAttribute(n, clean.join(';'));
17250 node.removeAttribute(n);
17256 for (var i = node.attributes.length-1; i > -1 ; i--) {
17257 var a = node.attributes[i];
17260 if (a.name.toLowerCase().substr(0,2)=='on') {
17261 node.removeAttribute(a.name);
17264 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17265 node.removeAttribute(a.name);
17268 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17269 cleanAttr(a.name,a.value); // fixme..
17272 if (a.name == 'style') {
17273 cleanStyle(a.name,a.value);
17276 /// clean up MS crap..
17277 // tecnically this should be a list of valid class'es..
17280 if (a.name == 'class') {
17281 if (a.value.match(/^Mso/)) {
17282 node.className = '';
17285 if (a.value.match(/body/)) {
17286 node.className = '';
17297 this.cleanUpChildren(node);
17302 * Clean up MS wordisms...
17304 cleanWord : function(node)
17307 var cleanWordChildren = function()
17309 if (!node.childNodes.length) {
17312 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17313 _t.cleanWord(node.childNodes[i]);
17319 this.cleanWord(this.doc.body);
17322 if (node.nodeName == "#text") {
17323 // clean up silly Windows -- stuff?
17326 if (node.nodeName == "#comment") {
17327 node.parentNode.removeChild(node);
17328 // clean up silly Windows -- stuff?
17332 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17333 node.parentNode.removeChild(node);
17337 // remove - but keep children..
17338 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17339 while (node.childNodes.length) {
17340 var cn = node.childNodes[0];
17341 node.removeChild(cn);
17342 node.parentNode.insertBefore(cn, node);
17344 node.parentNode.removeChild(node);
17345 cleanWordChildren();
17349 if (node.className.length) {
17351 var cn = node.className.split(/\W+/);
17353 Roo.each(cn, function(cls) {
17354 if (cls.match(/Mso[a-zA-Z]+/)) {
17359 node.className = cna.length ? cna.join(' ') : '';
17361 node.removeAttribute("class");
17365 if (node.hasAttribute("lang")) {
17366 node.removeAttribute("lang");
17369 if (node.hasAttribute("style")) {
17371 var styles = node.getAttribute("style").split(";");
17373 Roo.each(styles, function(s) {
17374 if (!s.match(/:/)) {
17377 var kv = s.split(":");
17378 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17381 // what ever is left... we allow.
17384 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17385 if (!nstyle.length) {
17386 node.removeAttribute('style');
17390 cleanWordChildren();
17394 domToHTML : function(currentElement, depth, nopadtext) {
17396 depth = depth || 0;
17397 nopadtext = nopadtext || false;
17399 if (!currentElement) {
17400 return this.domToHTML(this.doc.body);
17403 //Roo.log(currentElement);
17405 var allText = false;
17406 var nodeName = currentElement.nodeName;
17407 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17409 if (nodeName == '#text') {
17410 return currentElement.nodeValue;
17415 if (nodeName != 'BODY') {
17418 // Prints the node tagName, such as <A>, <IMG>, etc
17421 for(i = 0; i < currentElement.attributes.length;i++) {
17423 var aname = currentElement.attributes.item(i).name;
17424 if (!currentElement.attributes.item(i).value.length) {
17427 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17430 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17439 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17442 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17447 // Traverse the tree
17449 var currentElementChild = currentElement.childNodes.item(i);
17450 var allText = true;
17451 var innerHTML = '';
17453 while (currentElementChild) {
17454 // Formatting code (indent the tree so it looks nice on the screen)
17455 var nopad = nopadtext;
17456 if (lastnode == 'SPAN') {
17460 if (currentElementChild.nodeName == '#text') {
17461 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17462 if (!nopad && toadd.length > 80) {
17463 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17465 innerHTML += toadd;
17468 currentElementChild = currentElement.childNodes.item(i);
17474 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17476 // Recursively traverse the tree structure of the child node
17477 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17478 lastnode = currentElementChild.nodeName;
17480 currentElementChild=currentElement.childNodes.item(i);
17486 // The remaining code is mostly for formatting the tree
17487 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17492 ret+= "</"+tagName+">";
17498 // hide stuff that is not compatible
17512 * @event specialkey
17516 * @cfg {String} fieldClass @hide
17519 * @cfg {String} focusClass @hide
17522 * @cfg {String} autoCreate @hide
17525 * @cfg {String} inputType @hide
17528 * @cfg {String} invalidClass @hide
17531 * @cfg {String} invalidText @hide
17534 * @cfg {String} msgFx @hide
17537 * @cfg {String} validateOnBlur @hide
17541 Roo.HtmlEditorCore.white = [
17542 'area', 'br', 'img', 'input', 'hr', 'wbr',
17544 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17545 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17546 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17547 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17548 'table', 'ul', 'xmp',
17550 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17553 'dir', 'menu', 'ol', 'ul', 'dl',
17559 Roo.HtmlEditorCore.black = [
17560 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17562 'base', 'basefont', 'bgsound', 'blink', 'body',
17563 'frame', 'frameset', 'head', 'html', 'ilayer',
17564 'iframe', 'layer', 'link', 'meta', 'object',
17565 'script', 'style' ,'title', 'xml' // clean later..
17567 Roo.HtmlEditorCore.clean = [
17568 'script', 'style', 'title', 'xml'
17570 Roo.HtmlEditorCore.remove = [
17575 Roo.HtmlEditorCore.ablack = [
17579 Roo.HtmlEditorCore.aclean = [
17580 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17584 Roo.HtmlEditorCore.pwhite= [
17585 'http', 'https', 'mailto'
17588 // white listed style attributes.
17589 Roo.HtmlEditorCore.cwhite= [
17590 // 'text-align', /// default is to allow most things..
17596 // black listed style attributes.
17597 Roo.HtmlEditorCore.cblack= [
17598 // 'font-size' -- this can be set by the project
17602 Roo.HtmlEditorCore.swapCodes =[
17621 * @class Roo.bootstrap.HtmlEditor
17622 * @extends Roo.bootstrap.TextArea
17623 * Bootstrap HtmlEditor class
17626 * Create a new HtmlEditor
17627 * @param {Object} config The config object
17630 Roo.bootstrap.HtmlEditor = function(config){
17631 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17632 if (!this.toolbars) {
17633 this.toolbars = [];
17635 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17638 * @event initialize
17639 * Fires when the editor is fully initialized (including the iframe)
17640 * @param {HtmlEditor} this
17645 * Fires when the editor is first receives the focus. Any insertion must wait
17646 * until after this event.
17647 * @param {HtmlEditor} this
17651 * @event beforesync
17652 * Fires before the textarea is updated with content from the editor iframe. Return false
17653 * to cancel the sync.
17654 * @param {HtmlEditor} this
17655 * @param {String} html
17659 * @event beforepush
17660 * Fires before the iframe editor is updated with content from the textarea. Return false
17661 * to cancel the push.
17662 * @param {HtmlEditor} this
17663 * @param {String} html
17668 * Fires when the textarea is updated with content from the editor iframe.
17669 * @param {HtmlEditor} this
17670 * @param {String} html
17675 * Fires when the iframe editor is updated with content from the textarea.
17676 * @param {HtmlEditor} this
17677 * @param {String} html
17681 * @event editmodechange
17682 * Fires when the editor switches edit modes
17683 * @param {HtmlEditor} this
17684 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17686 editmodechange: true,
17688 * @event editorevent
17689 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17690 * @param {HtmlEditor} this
17694 * @event firstfocus
17695 * Fires when on first focus - needed by toolbars..
17696 * @param {HtmlEditor} this
17701 * Auto save the htmlEditor value as a file into Events
17702 * @param {HtmlEditor} this
17706 * @event savedpreview
17707 * preview the saved version of htmlEditor
17708 * @param {HtmlEditor} this
17715 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17719 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17724 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17729 * @cfg {Number} height (in pixels)
17733 * @cfg {Number} width (in pixels)
17738 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17741 stylesheets: false,
17746 // private properties
17747 validationEvent : false,
17749 initialized : false,
17752 onFocus : Roo.emptyFn,
17754 hideMode:'offsets',
17757 tbContainer : false,
17759 toolbarContainer :function() {
17760 return this.wrap.select('.x-html-editor-tb',true).first();
17764 * Protected method that will not generally be called directly. It
17765 * is called when the editor creates its toolbar. Override this method if you need to
17766 * add custom toolbar buttons.
17767 * @param {HtmlEditor} editor
17769 createToolbar : function(){
17771 Roo.log("create toolbars");
17773 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17774 this.toolbars[0].render(this.toolbarContainer());
17778 // if (!editor.toolbars || !editor.toolbars.length) {
17779 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17782 // for (var i =0 ; i < editor.toolbars.length;i++) {
17783 // editor.toolbars[i] = Roo.factory(
17784 // typeof(editor.toolbars[i]) == 'string' ?
17785 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17786 // Roo.bootstrap.HtmlEditor);
17787 // editor.toolbars[i].init(editor);
17793 onRender : function(ct, position)
17795 // Roo.log("Call onRender: " + this.xtype);
17797 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17799 this.wrap = this.inputEl().wrap({
17800 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17803 this.editorcore.onRender(ct, position);
17805 if (this.resizable) {
17806 this.resizeEl = new Roo.Resizable(this.wrap, {
17810 minHeight : this.height,
17811 height: this.height,
17812 handles : this.resizable,
17815 resize : function(r, w, h) {
17816 _t.onResize(w,h); // -something
17822 this.createToolbar(this);
17825 if(!this.width && this.resizable){
17826 this.setSize(this.wrap.getSize());
17828 if (this.resizeEl) {
17829 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17830 // should trigger onReize..
17836 onResize : function(w, h)
17838 Roo.log('resize: ' +w + ',' + h );
17839 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17843 if(this.inputEl() ){
17844 if(typeof w == 'number'){
17845 var aw = w - this.wrap.getFrameWidth('lr');
17846 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17849 if(typeof h == 'number'){
17850 var tbh = -11; // fixme it needs to tool bar size!
17851 for (var i =0; i < this.toolbars.length;i++) {
17852 // fixme - ask toolbars for heights?
17853 tbh += this.toolbars[i].el.getHeight();
17854 //if (this.toolbars[i].footer) {
17855 // tbh += this.toolbars[i].footer.el.getHeight();
17863 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17864 ah -= 5; // knock a few pixes off for look..
17865 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17869 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17870 this.editorcore.onResize(ew,eh);
17875 * Toggles the editor between standard and source edit mode.
17876 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17878 toggleSourceEdit : function(sourceEditMode)
17880 this.editorcore.toggleSourceEdit(sourceEditMode);
17882 if(this.editorcore.sourceEditMode){
17883 Roo.log('editor - showing textarea');
17886 // Roo.log(this.syncValue());
17888 this.inputEl().removeClass(['hide', 'x-hidden']);
17889 this.inputEl().dom.removeAttribute('tabIndex');
17890 this.inputEl().focus();
17892 Roo.log('editor - hiding textarea');
17894 // Roo.log(this.pushValue());
17897 this.inputEl().addClass(['hide', 'x-hidden']);
17898 this.inputEl().dom.setAttribute('tabIndex', -1);
17899 //this.deferFocus();
17902 if(this.resizable){
17903 this.setSize(this.wrap.getSize());
17906 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17909 // private (for BoxComponent)
17910 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17912 // private (for BoxComponent)
17913 getResizeEl : function(){
17917 // private (for BoxComponent)
17918 getPositionEl : function(){
17923 initEvents : function(){
17924 this.originalValue = this.getValue();
17928 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17931 // markInvalid : Roo.emptyFn,
17933 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17936 // clearInvalid : Roo.emptyFn,
17938 setValue : function(v){
17939 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17940 this.editorcore.pushValue();
17945 deferFocus : function(){
17946 this.focus.defer(10, this);
17950 focus : function(){
17951 this.editorcore.focus();
17957 onDestroy : function(){
17963 for (var i =0; i < this.toolbars.length;i++) {
17964 // fixme - ask toolbars for heights?
17965 this.toolbars[i].onDestroy();
17968 this.wrap.dom.innerHTML = '';
17969 this.wrap.remove();
17974 onFirstFocus : function(){
17975 //Roo.log("onFirstFocus");
17976 this.editorcore.onFirstFocus();
17977 for (var i =0; i < this.toolbars.length;i++) {
17978 this.toolbars[i].onFirstFocus();
17984 syncValue : function()
17986 this.editorcore.syncValue();
17989 pushValue : function()
17991 this.editorcore.pushValue();
17995 // hide stuff that is not compatible
18009 * @event specialkey
18013 * @cfg {String} fieldClass @hide
18016 * @cfg {String} focusClass @hide
18019 * @cfg {String} autoCreate @hide
18022 * @cfg {String} inputType @hide
18025 * @cfg {String} invalidClass @hide
18028 * @cfg {String} invalidText @hide
18031 * @cfg {String} msgFx @hide
18034 * @cfg {String} validateOnBlur @hide
18043 Roo.namespace('Roo.bootstrap.htmleditor');
18045 * @class Roo.bootstrap.HtmlEditorToolbar1
18050 new Roo.bootstrap.HtmlEditor({
18053 new Roo.bootstrap.HtmlEditorToolbar1({
18054 disable : { fonts: 1 , format: 1, ..., ... , ...],
18060 * @cfg {Object} disable List of elements to disable..
18061 * @cfg {Array} btns List of additional buttons.
18065 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18068 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18071 Roo.apply(this, config);
18073 // default disabled, based on 'good practice'..
18074 this.disable = this.disable || {};
18075 Roo.applyIf(this.disable, {
18078 specialElements : true
18080 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18082 this.editor = config.editor;
18083 this.editorcore = config.editor.editorcore;
18085 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18087 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18088 // dont call parent... till later.
18090 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18095 editorcore : false,
18100 "h1","h2","h3","h4","h5","h6",
18102 "abbr", "acronym", "address", "cite", "samp", "var",
18106 onRender : function(ct, position)
18108 // Roo.log("Call onRender: " + this.xtype);
18110 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18112 this.el.dom.style.marginBottom = '0';
18114 var editorcore = this.editorcore;
18115 var editor= this.editor;
18118 var btn = function(id,cmd , toggle, handler){
18120 var event = toggle ? 'toggle' : 'click';
18125 xns: Roo.bootstrap,
18128 enableToggle:toggle !== false,
18130 pressed : toggle ? false : null,
18133 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18134 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18143 xns: Roo.bootstrap,
18144 glyphicon : 'font',
18148 xns: Roo.bootstrap,
18152 Roo.each(this.formats, function(f) {
18153 style.menu.items.push({
18155 xns: Roo.bootstrap,
18156 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18161 editorcore.insertTag(this.tagname);
18168 children.push(style);
18171 btn('bold',false,true);
18172 btn('italic',false,true);
18173 btn('align-left', 'justifyleft',true);
18174 btn('align-center', 'justifycenter',true);
18175 btn('align-right' , 'justifyright',true);
18176 btn('link', false, false, function(btn) {
18177 //Roo.log("create link?");
18178 var url = prompt(this.createLinkText, this.defaultLinkValue);
18179 if(url && url != 'http:/'+'/'){
18180 this.editorcore.relayCmd('createlink', url);
18183 btn('list','insertunorderedlist',true);
18184 btn('pencil', false,true, function(btn){
18187 this.toggleSourceEdit(btn.pressed);
18193 xns: Roo.bootstrap,
18198 xns: Roo.bootstrap,
18203 cog.menu.items.push({
18205 xns: Roo.bootstrap,
18206 html : Clean styles,
18211 editorcore.insertTag(this.tagname);
18220 this.xtype = 'NavSimplebar';
18222 for(var i=0;i< children.length;i++) {
18224 this.buttons.add(this.addxtypeChild(children[i]));
18228 editor.on('editorevent', this.updateToolbar, this);
18230 onBtnClick : function(id)
18232 this.editorcore.relayCmd(id);
18233 this.editorcore.focus();
18237 * Protected method that will not generally be called directly. It triggers
18238 * a toolbar update by reading the markup state of the current selection in the editor.
18240 updateToolbar: function(){
18242 if(!this.editorcore.activated){
18243 this.editor.onFirstFocus(); // is this neeed?
18247 var btns = this.buttons;
18248 var doc = this.editorcore.doc;
18249 btns.get('bold').setActive(doc.queryCommandState('bold'));
18250 btns.get('italic').setActive(doc.queryCommandState('italic'));
18251 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18253 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18254 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18255 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18257 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18258 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18261 var ans = this.editorcore.getAllAncestors();
18262 if (this.formatCombo) {
18265 var store = this.formatCombo.store;
18266 this.formatCombo.setValue("");
18267 for (var i =0; i < ans.length;i++) {
18268 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18270 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18278 // hides menus... - so this cant be on a menu...
18279 Roo.bootstrap.MenuMgr.hideAll();
18281 Roo.bootstrap.MenuMgr.hideAll();
18282 //this.editorsyncValue();
18284 onFirstFocus: function() {
18285 this.buttons.each(function(item){
18289 toggleSourceEdit : function(sourceEditMode){
18292 if(sourceEditMode){
18293 Roo.log("disabling buttons");
18294 this.buttons.each( function(item){
18295 if(item.cmd != 'pencil'){
18301 Roo.log("enabling buttons");
18302 if(this.editorcore.initialized){
18303 this.buttons.each( function(item){
18309 Roo.log("calling toggole on editor");
18310 // tell the editor that it's been pressed..
18311 this.editor.toggleSourceEdit(sourceEditMode);
18321 * @class Roo.bootstrap.Table.AbstractSelectionModel
18322 * @extends Roo.util.Observable
18323 * Abstract base class for grid SelectionModels. It provides the interface that should be
18324 * implemented by descendant classes. This class should not be directly instantiated.
18327 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18328 this.locked = false;
18329 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18333 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18334 /** @ignore Called by the grid automatically. Do not call directly. */
18335 init : function(grid){
18341 * Locks the selections.
18344 this.locked = true;
18348 * Unlocks the selections.
18350 unlock : function(){
18351 this.locked = false;
18355 * Returns true if the selections are locked.
18356 * @return {Boolean}
18358 isLocked : function(){
18359 return this.locked;
18363 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18364 * @class Roo.bootstrap.Table.RowSelectionModel
18365 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18366 * It supports multiple selections and keyboard selection/navigation.
18368 * @param {Object} config
18371 Roo.bootstrap.Table.RowSelectionModel = function(config){
18372 Roo.apply(this, config);
18373 this.selections = new Roo.util.MixedCollection(false, function(o){
18378 this.lastActive = false;
18382 * @event selectionchange
18383 * Fires when the selection changes
18384 * @param {SelectionModel} this
18386 "selectionchange" : true,
18388 * @event afterselectionchange
18389 * Fires after the selection changes (eg. by key press or clicking)
18390 * @param {SelectionModel} this
18392 "afterselectionchange" : true,
18394 * @event beforerowselect
18395 * Fires when a row is selected being selected, return false to cancel.
18396 * @param {SelectionModel} this
18397 * @param {Number} rowIndex The selected index
18398 * @param {Boolean} keepExisting False if other selections will be cleared
18400 "beforerowselect" : true,
18403 * Fires when a row is selected.
18404 * @param {SelectionModel} this
18405 * @param {Number} rowIndex The selected index
18406 * @param {Roo.data.Record} r The record
18408 "rowselect" : true,
18410 * @event rowdeselect
18411 * Fires when a row is deselected.
18412 * @param {SelectionModel} this
18413 * @param {Number} rowIndex The selected index
18415 "rowdeselect" : true
18417 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18418 this.locked = false;
18421 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18423 * @cfg {Boolean} singleSelect
18424 * True to allow selection of only one row at a time (defaults to false)
18426 singleSelect : false,
18429 initEvents : function(){
18431 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18432 this.grid.on("mousedown", this.handleMouseDown, this);
18433 }else{ // allow click to work like normal
18434 this.grid.on("rowclick", this.handleDragableRowClick, this);
18437 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18438 "up" : function(e){
18440 this.selectPrevious(e.shiftKey);
18441 }else if(this.last !== false && this.lastActive !== false){
18442 var last = this.last;
18443 this.selectRange(this.last, this.lastActive-1);
18444 this.grid.getView().focusRow(this.lastActive);
18445 if(last !== false){
18449 this.selectFirstRow();
18451 this.fireEvent("afterselectionchange", this);
18453 "down" : function(e){
18455 this.selectNext(e.shiftKey);
18456 }else if(this.last !== false && this.lastActive !== false){
18457 var last = this.last;
18458 this.selectRange(this.last, this.lastActive+1);
18459 this.grid.getView().focusRow(this.lastActive);
18460 if(last !== false){
18464 this.selectFirstRow();
18466 this.fireEvent("afterselectionchange", this);
18471 var view = this.grid.view;
18472 view.on("refresh", this.onRefresh, this);
18473 view.on("rowupdated", this.onRowUpdated, this);
18474 view.on("rowremoved", this.onRemove, this);
18478 onRefresh : function(){
18479 var ds = this.grid.dataSource, i, v = this.grid.view;
18480 var s = this.selections;
18481 s.each(function(r){
18482 if((i = ds.indexOfId(r.id)) != -1){
18491 onRemove : function(v, index, r){
18492 this.selections.remove(r);
18496 onRowUpdated : function(v, index, r){
18497 if(this.isSelected(r)){
18498 v.onRowSelect(index);
18504 * @param {Array} records The records to select
18505 * @param {Boolean} keepExisting (optional) True to keep existing selections
18507 selectRecords : function(records, keepExisting){
18509 this.clearSelections();
18511 var ds = this.grid.dataSource;
18512 for(var i = 0, len = records.length; i < len; i++){
18513 this.selectRow(ds.indexOf(records[i]), true);
18518 * Gets the number of selected rows.
18521 getCount : function(){
18522 return this.selections.length;
18526 * Selects the first row in the grid.
18528 selectFirstRow : function(){
18533 * Select the last row.
18534 * @param {Boolean} keepExisting (optional) True to keep existing selections
18536 selectLastRow : function(keepExisting){
18537 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18541 * Selects the row immediately following the last selected row.
18542 * @param {Boolean} keepExisting (optional) True to keep existing selections
18544 selectNext : function(keepExisting){
18545 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18546 this.selectRow(this.last+1, keepExisting);
18547 this.grid.getView().focusRow(this.last);
18552 * Selects the row that precedes the last selected row.
18553 * @param {Boolean} keepExisting (optional) True to keep existing selections
18555 selectPrevious : function(keepExisting){
18557 this.selectRow(this.last-1, keepExisting);
18558 this.grid.getView().focusRow(this.last);
18563 * Returns the selected records
18564 * @return {Array} Array of selected records
18566 getSelections : function(){
18567 return [].concat(this.selections.items);
18571 * Returns the first selected record.
18574 getSelected : function(){
18575 return this.selections.itemAt(0);
18580 * Clears all selections.
18582 clearSelections : function(fast){
18583 if(this.locked) return;
18585 var ds = this.grid.dataSource;
18586 var s = this.selections;
18587 s.each(function(r){
18588 this.deselectRow(ds.indexOfId(r.id));
18592 this.selections.clear();
18599 * Selects all rows.
18601 selectAll : function(){
18602 if(this.locked) return;
18603 this.selections.clear();
18604 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18605 this.selectRow(i, true);
18610 * Returns True if there is a selection.
18611 * @return {Boolean}
18613 hasSelection : function(){
18614 return this.selections.length > 0;
18618 * Returns True if the specified row is selected.
18619 * @param {Number/Record} record The record or index of the record to check
18620 * @return {Boolean}
18622 isSelected : function(index){
18623 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18624 return (r && this.selections.key(r.id) ? true : false);
18628 * Returns True if the specified record id is selected.
18629 * @param {String} id The id of record to check
18630 * @return {Boolean}
18632 isIdSelected : function(id){
18633 return (this.selections.key(id) ? true : false);
18637 handleMouseDown : function(e, t){
18638 var view = this.grid.getView(), rowIndex;
18639 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18642 if(e.shiftKey && this.last !== false){
18643 var last = this.last;
18644 this.selectRange(last, rowIndex, e.ctrlKey);
18645 this.last = last; // reset the last
18646 view.focusRow(rowIndex);
18648 var isSelected = this.isSelected(rowIndex);
18649 if(e.button !== 0 && isSelected){
18650 view.focusRow(rowIndex);
18651 }else if(e.ctrlKey && isSelected){
18652 this.deselectRow(rowIndex);
18653 }else if(!isSelected){
18654 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18655 view.focusRow(rowIndex);
18658 this.fireEvent("afterselectionchange", this);
18661 handleDragableRowClick : function(grid, rowIndex, e)
18663 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18664 this.selectRow(rowIndex, false);
18665 grid.view.focusRow(rowIndex);
18666 this.fireEvent("afterselectionchange", this);
18671 * Selects multiple rows.
18672 * @param {Array} rows Array of the indexes of the row to select
18673 * @param {Boolean} keepExisting (optional) True to keep existing selections
18675 selectRows : function(rows, keepExisting){
18677 this.clearSelections();
18679 for(var i = 0, len = rows.length; i < len; i++){
18680 this.selectRow(rows[i], true);
18685 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18686 * @param {Number} startRow The index of the first row in the range
18687 * @param {Number} endRow The index of the last row in the range
18688 * @param {Boolean} keepExisting (optional) True to retain existing selections
18690 selectRange : function(startRow, endRow, keepExisting){
18691 if(this.locked) return;
18693 this.clearSelections();
18695 if(startRow <= endRow){
18696 for(var i = startRow; i <= endRow; i++){
18697 this.selectRow(i, true);
18700 for(var i = startRow; i >= endRow; i--){
18701 this.selectRow(i, true);
18707 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18708 * @param {Number} startRow The index of the first row in the range
18709 * @param {Number} endRow The index of the last row in the range
18711 deselectRange : function(startRow, endRow, preventViewNotify){
18712 if(this.locked) return;
18713 for(var i = startRow; i <= endRow; i++){
18714 this.deselectRow(i, preventViewNotify);
18720 * @param {Number} row The index of the row to select
18721 * @param {Boolean} keepExisting (optional) True to keep existing selections
18723 selectRow : function(index, keepExisting, preventViewNotify){
18724 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18725 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18726 if(!keepExisting || this.singleSelect){
18727 this.clearSelections();
18729 var r = this.grid.dataSource.getAt(index);
18730 this.selections.add(r);
18731 this.last = this.lastActive = index;
18732 if(!preventViewNotify){
18733 this.grid.getView().onRowSelect(index);
18735 this.fireEvent("rowselect", this, index, r);
18736 this.fireEvent("selectionchange", this);
18742 * @param {Number} row The index of the row to deselect
18744 deselectRow : function(index, preventViewNotify){
18745 if(this.locked) return;
18746 if(this.last == index){
18749 if(this.lastActive == index){
18750 this.lastActive = false;
18752 var r = this.grid.dataSource.getAt(index);
18753 this.selections.remove(r);
18754 if(!preventViewNotify){
18755 this.grid.getView().onRowDeselect(index);
18757 this.fireEvent("rowdeselect", this, index);
18758 this.fireEvent("selectionchange", this);
18762 restoreLast : function(){
18764 this.last = this._last;
18769 acceptsNav : function(row, col, cm){
18770 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18774 onEditorKey : function(field, e){
18775 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18780 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18782 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18784 }else if(k == e.ENTER && !e.ctrlKey){
18788 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18790 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18792 }else if(k == e.ESC){
18796 g.startEditing(newCell[0], newCell[1]);
18801 * Ext JS Library 1.1.1
18802 * Copyright(c) 2006-2007, Ext JS, LLC.
18804 * Originally Released Under LGPL - original licence link has changed is not relivant.
18807 * <script type="text/javascript">
18811 * @class Roo.bootstrap.PagingToolbar
18813 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18815 * Create a new PagingToolbar
18816 * @param {Object} config The config object
18818 Roo.bootstrap.PagingToolbar = function(config)
18820 // old args format still supported... - xtype is prefered..
18821 // created from xtype...
18822 var ds = config.dataSource;
18823 this.toolbarItems = [];
18824 if (config.items) {
18825 this.toolbarItems = config.items;
18826 // config.items = [];
18829 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18836 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18840 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18842 * @cfg {Roo.data.Store} dataSource
18843 * The underlying data store providing the paged data
18846 * @cfg {String/HTMLElement/Element} container
18847 * container The id or element that will contain the toolbar
18850 * @cfg {Boolean} displayInfo
18851 * True to display the displayMsg (defaults to false)
18854 * @cfg {Number} pageSize
18855 * The number of records to display per page (defaults to 20)
18859 * @cfg {String} displayMsg
18860 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18862 displayMsg : 'Displaying {0} - {1} of {2}',
18864 * @cfg {String} emptyMsg
18865 * The message to display when no records are found (defaults to "No data to display")
18867 emptyMsg : 'No data to display',
18869 * Customizable piece of the default paging text (defaults to "Page")
18872 beforePageText : "Page",
18874 * Customizable piece of the default paging text (defaults to "of %0")
18877 afterPageText : "of {0}",
18879 * Customizable piece of the default paging text (defaults to "First Page")
18882 firstText : "First Page",
18884 * Customizable piece of the default paging text (defaults to "Previous Page")
18887 prevText : "Previous Page",
18889 * Customizable piece of the default paging text (defaults to "Next Page")
18892 nextText : "Next Page",
18894 * Customizable piece of the default paging text (defaults to "Last Page")
18897 lastText : "Last Page",
18899 * Customizable piece of the default paging text (defaults to "Refresh")
18902 refreshText : "Refresh",
18906 onRender : function(ct, position)
18908 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18909 this.navgroup.parentId = this.id;
18910 this.navgroup.onRender(this.el, null);
18911 // add the buttons to the navgroup
18913 if(this.displayInfo){
18914 Roo.log(this.el.select('ul.navbar-nav',true).first());
18915 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18916 this.displayEl = this.el.select('.x-paging-info', true).first();
18917 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18918 // this.displayEl = navel.el.select('span',true).first();
18924 Roo.each(_this.buttons, function(e){
18925 Roo.factory(e).onRender(_this.el, null);
18929 Roo.each(_this.toolbarItems, function(e) {
18930 _this.navgroup.addItem(e);
18933 this.first = this.navgroup.addItem({
18934 tooltip: this.firstText,
18936 icon : 'fa fa-backward',
18938 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18941 this.prev = this.navgroup.addItem({
18942 tooltip: this.prevText,
18944 icon : 'fa fa-step-backward',
18946 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18948 //this.addSeparator();
18951 var field = this.navgroup.addItem( {
18953 cls : 'x-paging-position',
18955 html : this.beforePageText +
18956 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18957 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18960 this.field = field.el.select('input', true).first();
18961 this.field.on("keydown", this.onPagingKeydown, this);
18962 this.field.on("focus", function(){this.dom.select();});
18965 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18966 //this.field.setHeight(18);
18967 //this.addSeparator();
18968 this.next = this.navgroup.addItem({
18969 tooltip: this.nextText,
18971 html : ' <i class="fa fa-step-forward">',
18973 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18975 this.last = this.navgroup.addItem({
18976 tooltip: this.lastText,
18977 icon : 'fa fa-forward',
18980 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18982 //this.addSeparator();
18983 this.loading = this.navgroup.addItem({
18984 tooltip: this.refreshText,
18985 icon: 'fa fa-refresh',
18987 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18993 updateInfo : function(){
18994 if(this.displayEl){
18995 var count = this.ds.getCount();
18996 var msg = count == 0 ?
19000 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19002 this.displayEl.update(msg);
19007 onLoad : function(ds, r, o){
19008 this.cursor = o.params ? o.params.start : 0;
19009 var d = this.getPageData(),
19013 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19014 this.field.dom.value = ap;
19015 this.first.setDisabled(ap == 1);
19016 this.prev.setDisabled(ap == 1);
19017 this.next.setDisabled(ap == ps);
19018 this.last.setDisabled(ap == ps);
19019 this.loading.enable();
19024 getPageData : function(){
19025 var total = this.ds.getTotalCount();
19028 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19029 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19034 onLoadError : function(){
19035 this.loading.enable();
19039 onPagingKeydown : function(e){
19040 var k = e.getKey();
19041 var d = this.getPageData();
19043 var v = this.field.dom.value, pageNum;
19044 if(!v || isNaN(pageNum = parseInt(v, 10))){
19045 this.field.dom.value = d.activePage;
19048 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19049 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19052 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))
19054 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19055 this.field.dom.value = pageNum;
19056 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19059 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19061 var v = this.field.dom.value, pageNum;
19062 var increment = (e.shiftKey) ? 10 : 1;
19063 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19065 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19066 this.field.dom.value = d.activePage;
19069 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19071 this.field.dom.value = parseInt(v, 10) + increment;
19072 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19073 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19080 beforeLoad : function(){
19082 this.loading.disable();
19087 onClick : function(which){
19094 ds.load({params:{start: 0, limit: this.pageSize}});
19097 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19100 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19103 var total = ds.getTotalCount();
19104 var extra = total % this.pageSize;
19105 var lastStart = extra ? (total - extra) : total-this.pageSize;
19106 ds.load({params:{start: lastStart, limit: this.pageSize}});
19109 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19115 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19116 * @param {Roo.data.Store} store The data store to unbind
19118 unbind : function(ds){
19119 ds.un("beforeload", this.beforeLoad, this);
19120 ds.un("load", this.onLoad, this);
19121 ds.un("loadexception", this.onLoadError, this);
19122 ds.un("remove", this.updateInfo, this);
19123 ds.un("add", this.updateInfo, this);
19124 this.ds = undefined;
19128 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19129 * @param {Roo.data.Store} store The data store to bind
19131 bind : function(ds){
19132 ds.on("beforeload", this.beforeLoad, this);
19133 ds.on("load", this.onLoad, this);
19134 ds.on("loadexception", this.onLoadError, this);
19135 ds.on("remove", this.updateInfo, this);
19136 ds.on("add", this.updateInfo, this);
19147 * @class Roo.bootstrap.MessageBar
19148 * @extends Roo.bootstrap.Component
19149 * Bootstrap MessageBar class
19150 * @cfg {String} html contents of the MessageBar
19151 * @cfg {String} weight (info | success | warning | danger) default info
19152 * @cfg {String} beforeClass insert the bar before the given class
19153 * @cfg {Boolean} closable (true | false) default false
19154 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19157 * Create a new Element
19158 * @param {Object} config The config object
19161 Roo.bootstrap.MessageBar = function(config){
19162 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19165 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19171 beforeClass: 'bootstrap-sticky-wrap',
19173 getAutoCreate : function(){
19177 cls: 'alert alert-dismissable alert-' + this.weight,
19182 html: this.html || ''
19188 cfg.cls += ' alert-messages-fixed';
19202 onRender : function(ct, position)
19204 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19207 var cfg = Roo.apply({}, this.getAutoCreate());
19211 cfg.cls += ' ' + this.cls;
19214 cfg.style = this.style;
19216 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19218 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19221 this.el.select('>button.close').on('click', this.hide, this);
19227 if (!this.rendered) {
19233 this.fireEvent('show', this);
19239 if (!this.rendered) {
19245 this.fireEvent('hide', this);
19248 update : function()
19250 // var e = this.el.dom.firstChild;
19252 // if(this.closable){
19253 // e = e.nextSibling;
19256 // e.data = this.html || '';
19258 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19274 * @class Roo.bootstrap.Graph
19275 * @extends Roo.bootstrap.Component
19276 * Bootstrap Graph class
19280 @cfg {String} graphtype bar | vbar | pie
19281 @cfg {number} g_x coodinator | centre x (pie)
19282 @cfg {number} g_y coodinator | centre y (pie)
19283 @cfg {number} g_r radius (pie)
19284 @cfg {number} g_height height of the chart (respected by all elements in the set)
19285 @cfg {number} g_width width of the chart (respected by all elements in the set)
19286 @cfg {Object} title The title of the chart
19289 -opts (object) options for the chart
19291 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19292 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19294 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.
19295 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19297 o stretch (boolean)
19299 -opts (object) options for the pie
19302 o startAngle (number)
19303 o endAngle (number)
19307 * Create a new Input
19308 * @param {Object} config The config object
19311 Roo.bootstrap.Graph = function(config){
19312 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19318 * The img click event for the img.
19319 * @param {Roo.EventObject} e
19325 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19336 //g_colors: this.colors,
19343 getAutoCreate : function(){
19354 onRender : function(ct,position){
19355 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19356 this.raphael = Raphael(this.el.dom);
19358 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19359 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19360 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19361 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19363 r.text(160, 10, "Single Series Chart").attr(txtattr);
19364 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19365 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19366 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19368 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19369 r.barchart(330, 10, 300, 220, data1);
19370 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19371 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19374 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19375 // r.barchart(30, 30, 560, 250, xdata, {
19376 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19377 // axis : "0 0 1 1",
19378 // axisxlabels : xdata
19379 // //yvalues : cols,
19382 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19384 // this.load(null,xdata,{
19385 // axis : "0 0 1 1",
19386 // axisxlabels : xdata
19391 load : function(graphtype,xdata,opts){
19392 this.raphael.clear();
19394 graphtype = this.graphtype;
19399 var r = this.raphael,
19400 fin = function () {
19401 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19403 fout = function () {
19404 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19406 pfin = function() {
19407 this.sector.stop();
19408 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19411 this.label[0].stop();
19412 this.label[0].attr({ r: 7.5 });
19413 this.label[1].attr({ "font-weight": 800 });
19416 pfout = function() {
19417 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19420 this.label[0].animate({ r: 5 }, 500, "bounce");
19421 this.label[1].attr({ "font-weight": 400 });
19427 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19430 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19433 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19434 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19436 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19443 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19448 setTitle: function(o)
19453 initEvents: function() {
19456 this.el.on('click', this.onClick, this);
19460 onClick : function(e)
19462 Roo.log('img onclick');
19463 this.fireEvent('click', this, e);
19475 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19478 * @class Roo.bootstrap.dash.NumberBox
19479 * @extends Roo.bootstrap.Component
19480 * Bootstrap NumberBox class
19481 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19482 * @cfg {String} headline Box headline
19483 * @cfg {String} content Box content
19484 * @cfg {String} icon Box icon
19485 * @cfg {String} footer Footer text
19486 * @cfg {String} fhref Footer href
19489 * Create a new NumberBox
19490 * @param {Object} config The config object
19494 Roo.bootstrap.dash.NumberBox = function(config){
19495 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19499 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19509 getAutoCreate : function(){
19513 cls : 'small-box bg-' + this.bgcolor,
19521 cls : 'roo-headline',
19522 html : this.headline
19526 cls : 'roo-content',
19527 html : this.content
19541 cls : 'ion ' + this.icon
19550 cls : 'small-box-footer',
19551 href : this.fhref || '#',
19555 cfg.cn.push(footer);
19562 onRender : function(ct,position){
19563 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19570 setHeadline: function (value)
19572 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19575 setFooter: function (value, href)
19577 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19580 this.el.select('a.small-box-footer',true).first().attr('href', href);
19585 setContent: function (value)
19587 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19590 initEvents: function()
19604 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19607 * @class Roo.bootstrap.dash.TabBox
19608 * @extends Roo.bootstrap.Component
19609 * Bootstrap TabBox class
19610 * @cfg {String} title Title of the TabBox
19611 * @cfg {String} icon Icon of the TabBox
19612 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19615 * Create a new TabBox
19616 * @param {Object} config The config object
19620 Roo.bootstrap.dash.TabBox = function(config){
19621 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19626 * When a pane is added
19627 * @param {Roo.bootstrap.dash.TabPane} pane
19634 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19640 getChildContainer : function()
19642 return this.el.select('.tab-content', true).first();
19645 getAutoCreate : function(){
19649 cls: 'pull-left header',
19657 cls: 'fa ' + this.icon
19664 cls: 'nav-tabs-custom',
19668 cls: 'nav nav-tabs pull-right',
19675 cls: 'tab-content no-padding',
19683 initEvents : function()
19685 //Roo.log('add add pane handler');
19686 this.on('addpane', this.onAddPane, this);
19689 * Updates the box title
19690 * @param {String} html to set the title to.
19692 setTitle : function(value)
19694 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19696 onAddPane : function(pane)
19698 //Roo.log('addpane');
19700 // tabs are rendere left to right..
19701 if(!this.showtabs){
19705 var ctr = this.el.select('.nav-tabs', true).first();
19708 var existing = ctr.select('.nav-tab',true);
19709 var qty = existing.getCount();;
19712 var tab = ctr.createChild({
19714 cls : 'nav-tab' + (qty ? '' : ' active'),
19722 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19725 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19727 pane.el.addClass('active');
19732 onTabClick : function(ev,un,ob,pane)
19734 //Roo.log('tab - prev default');
19735 ev.preventDefault();
19738 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19739 pane.tab.addClass('active');
19740 //Roo.log(pane.title);
19741 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19742 // technically we should have a deactivate event.. but maybe add later.
19743 // and it should not de-activate the selected tab...
19745 pane.el.addClass('active');
19746 pane.fireEvent('activate');
19761 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19763 * @class Roo.bootstrap.TabPane
19764 * @extends Roo.bootstrap.Component
19765 * Bootstrap TabPane class
19766 * @cfg {Boolean} active (false | true) Default false
19767 * @cfg {String} title title of panel
19771 * Create a new TabPane
19772 * @param {Object} config The config object
19775 Roo.bootstrap.dash.TabPane = function(config){
19776 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19782 * When a pane is activated
19783 * @param {Roo.bootstrap.dash.TabPane} pane
19790 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19795 // the tabBox that this is attached to.
19798 getAutoCreate : function()
19806 cfg.cls += ' active';
19811 initEvents : function()
19813 //Roo.log('trigger add pane handler');
19814 this.parent().fireEvent('addpane', this)
19818 * Updates the tab title
19819 * @param {String} html to set the title to.
19821 setTitle: function(str)
19827 this.tab.select('a', true).first().dom.innerHTML = str;
19844 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19847 * @class Roo.bootstrap.menu.Menu
19848 * @extends Roo.bootstrap.Component
19849 * Bootstrap Menu class - container for Menu
19850 * @cfg {String} html Text of the menu
19851 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19852 * @cfg {String} icon Font awesome icon
19853 * @cfg {String} pos Menu align to (top | bottom) default bottom
19857 * Create a new Menu
19858 * @param {Object} config The config object
19862 Roo.bootstrap.menu.Menu = function(config){
19863 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19867 * @event beforeshow
19868 * Fires before this menu is displayed
19869 * @param {Roo.bootstrap.menu.Menu} this
19873 * @event beforehide
19874 * Fires before this menu is hidden
19875 * @param {Roo.bootstrap.menu.Menu} this
19880 * Fires after this menu is displayed
19881 * @param {Roo.bootstrap.menu.Menu} this
19886 * Fires after this menu is hidden
19887 * @param {Roo.bootstrap.menu.Menu} this
19892 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19893 * @param {Roo.bootstrap.menu.Menu} this
19894 * @param {Roo.EventObject} e
19901 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19905 weight : 'default',
19910 getChildContainer : function() {
19911 if(this.isSubMenu){
19915 return this.el.select('ul.dropdown-menu', true).first();
19918 getAutoCreate : function()
19923 cls : 'roo-menu-text',
19931 cls : 'fa ' + this.icon
19942 cls : 'dropdown-button btn btn-' + this.weight,
19947 cls : 'dropdown-toggle btn btn-' + this.weight,
19957 cls : 'dropdown-menu'
19963 if(this.pos == 'top'){
19964 cfg.cls += ' dropup';
19967 if(this.isSubMenu){
19970 cls : 'dropdown-menu'
19977 onRender : function(ct, position)
19979 this.isSubMenu = ct.hasClass('dropdown-submenu');
19981 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19984 initEvents : function()
19986 if(this.isSubMenu){
19990 this.hidden = true;
19992 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19993 this.triggerEl.on('click', this.onTriggerPress, this);
19995 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19996 this.buttonEl.on('click', this.onClick, this);
20002 if(this.isSubMenu){
20006 return this.el.select('ul.dropdown-menu', true).first();
20009 onClick : function(e)
20011 this.fireEvent("click", this, e);
20014 onTriggerPress : function(e)
20016 if (this.isVisible()) {
20023 isVisible : function(){
20024 return !this.hidden;
20029 this.fireEvent("beforeshow", this);
20031 this.hidden = false;
20032 this.el.addClass('open');
20034 Roo.get(document).on("mouseup", this.onMouseUp, this);
20036 this.fireEvent("show", this);
20043 this.fireEvent("beforehide", this);
20045 this.hidden = true;
20046 this.el.removeClass('open');
20048 Roo.get(document).un("mouseup", this.onMouseUp);
20050 this.fireEvent("hide", this);
20053 onMouseUp : function()
20067 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20070 * @class Roo.bootstrap.menu.Item
20071 * @extends Roo.bootstrap.Component
20072 * Bootstrap MenuItem class
20073 * @cfg {Boolean} submenu (true | false) default false
20074 * @cfg {String} html text of the item
20075 * @cfg {String} href the link
20076 * @cfg {Boolean} disable (true | false) default false
20077 * @cfg {Boolean} preventDefault (true | false) default true
20078 * @cfg {String} icon Font awesome icon
20079 * @cfg {String} pos Submenu align to (left | right) default right
20083 * Create a new Item
20084 * @param {Object} config The config object
20088 Roo.bootstrap.menu.Item = function(config){
20089 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20093 * Fires when the mouse is hovering over this menu
20094 * @param {Roo.bootstrap.menu.Item} this
20095 * @param {Roo.EventObject} e
20100 * Fires when the mouse exits this menu
20101 * @param {Roo.bootstrap.menu.Item} this
20102 * @param {Roo.EventObject} e
20108 * The raw click event for the entire grid.
20109 * @param {Roo.EventObject} e
20115 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20120 preventDefault: true,
20125 getAutoCreate : function()
20130 cls : 'roo-menu-item-text',
20138 cls : 'fa ' + this.icon
20147 href : this.href || '#',
20154 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20158 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20160 if(this.pos == 'left'){
20161 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20168 initEvents : function()
20170 this.el.on('mouseover', this.onMouseOver, this);
20171 this.el.on('mouseout', this.onMouseOut, this);
20173 this.el.select('a', true).first().on('click', this.onClick, this);
20177 onClick : function(e)
20179 if(this.preventDefault){
20180 e.preventDefault();
20183 this.fireEvent("click", this, e);
20186 onMouseOver : function(e)
20188 if(this.submenu && this.pos == 'left'){
20189 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20192 this.fireEvent("mouseover", this, e);
20195 onMouseOut : function(e)
20197 this.fireEvent("mouseout", this, e);
20209 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20212 * @class Roo.bootstrap.menu.Separator
20213 * @extends Roo.bootstrap.Component
20214 * Bootstrap Separator class
20217 * Create a new Separator
20218 * @param {Object} config The config object
20222 Roo.bootstrap.menu.Separator = function(config){
20223 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20226 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20228 getAutoCreate : function(){