4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr](false));
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr](false));
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr](true));
241 // then add the element..
249 if (typeof (tree.menu) != 'undefined') {
250 tree.menu.parentType = cn.xtype;
251 tree.menu.triggerEl = cn.el;
252 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
256 if (!tree.items || !tree.items.length) {
260 var items = tree.items;
263 //Roo.log(items.length);
265 for(var i =0;i < items.length;i++) {
266 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
287 * @class Roo.bootstrap.Body
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Body class
293 * @param {Object} config The config object
296 Roo.bootstrap.Body = function(config){
297 Roo.bootstrap.Body.superclass.constructor.call(this, config);
298 this.el = Roo.get(document.body);
299 if (this.cls && this.cls.length) {
300 Roo.get(document.body).addClass(this.cls);
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
309 onRender : function(ct, position)
311 /* Roo.log("Roo.bootstrap.Body - onRender");
312 if (this.cls && this.cls.length) {
313 Roo.get(document.body).addClass(this.cls);
333 * @class Roo.bootstrap.ButtonGroup
334 * @extends Roo.bootstrap.Component
335 * Bootstrap ButtonGroup class
336 * @cfg {String} size lg | sm | xs (default empty normal)
337 * @cfg {String} align vertical | justified (default none)
338 * @cfg {String} direction up | down (default down)
339 * @cfg {Boolean} toolbar false | true
340 * @cfg {Boolean} btn true | false
345 * @param {Object} config The config object
348 Roo.bootstrap.ButtonGroup = function(config){
349 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
360 getAutoCreate : function(){
366 cfg.html = this.html || cfg.html;
377 if (['vertical','justified'].indexOf(this.align)!==-1) {
378 cfg.cls = 'btn-group-' + this.align;
380 if (this.align == 'justified') {
381 console.log(this.items);
385 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386 cfg.cls += ' btn-group-' + this.size;
389 if (this.direction == 'up') {
390 cfg.cls += ' dropup' ;
406 * @class Roo.bootstrap.Button
407 * @extends Roo.bootstrap.Component
408 * Bootstrap Button class
409 * @cfg {String} html The button content
410 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411 * @cfg {String} size empty | lg | sm | xs
412 * @cfg {String} tag empty | a | input | submit
413 * @cfg {String} href empty or href
414 * @cfg {Boolean} disabled false | true
415 * @cfg {Boolean} isClose false | true
416 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
417 * @cfg {String} badge text for badge
418 * @cfg {String} theme default (or empty) | glow
419 * @cfg {Boolean} inverse false | true
420 * @cfg {Boolean} toggle false | true
421 * @cfg {String} ontext text for on toggle state
422 * @cfg {String} offtext text for off toggle state
423 * @cfg {Boolean} defaulton true | false
424 * @cfg {Boolean} preventDefault (true | false) default true
425 * @cfg {Boolean} removeClass true | false remove the standard class..
426 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
429 * Create a new button
430 * @param {Object} config The config object
434 Roo.bootstrap.Button = function(config){
435 Roo.bootstrap.Button.superclass.constructor.call(this, config);
440 * When a butotn is pressed
441 * @param {Roo.EventObject} e
446 * After the button has been toggles
447 * @param {Roo.EventObject} e
448 * @param {boolean} pressed (also available as button.pressed)
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
472 preventDefault: true,
481 getAutoCreate : function(){
489 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
495 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
497 if (this.toggle == true) {
500 cls: 'slider-frame roo-button',
505 'data-off-text':'OFF',
506 cls: 'slider-button',
512 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513 cfg.cls += ' '+this.weight;
522 cfg["aria-hidden"] = true;
524 cfg.html = "×";
530 if (this.theme==='default') {
531 cfg.cls = 'btn roo-button';
533 //if (this.parentType != 'Navbar') {
534 this.weight = this.weight.length ? this.weight : 'default';
536 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
538 cfg.cls += ' btn-' + this.weight;
540 } else if (this.theme==='glow') {
543 cfg.cls = 'btn-glow roo-button';
545 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
547 cfg.cls += ' ' + this.weight;
553 this.cls += ' inverse';
558 cfg.cls += ' active';
562 cfg.disabled = 'disabled';
566 Roo.log('changing to ul' );
568 this.glyphicon = 'caret';
571 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
573 //gsRoo.log(this.parentType);
574 if (this.parentType === 'Navbar' && !this.parent().bar) {
575 Roo.log('changing to li?');
584 href : this.href || '#'
587 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
588 cfg.cls += ' dropdown';
595 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
597 if (this.glyphicon) {
598 cfg.html = ' ' + cfg.html;
603 cls: 'glyphicon glyphicon-' + this.glyphicon
613 // cfg.cls='btn roo-button';
617 var value = cfg.html;
622 cls: 'glyphicon glyphicon-' + this.glyphicon,
641 cfg.cls += ' dropdown';
642 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
645 if (cfg.tag !== 'a' && this.href !== '') {
646 throw "Tag must be a to set href.";
647 } else if (this.href.length > 0) {
648 cfg.href = this.href;
651 if(this.removeClass){
656 cfg.target = this.target;
661 initEvents: function() {
662 // Roo.log('init events?');
663 // Roo.log(this.el.dom);
666 if (typeof (this.menu) != 'undefined') {
667 this.menu.parentType = this.xtype;
668 this.menu.triggerEl = this.el;
669 this.addxtype(Roo.apply({}, this.menu));
673 if (this.el.hasClass('roo-button')) {
674 this.el.on('click', this.onClick, this);
676 this.el.select('.roo-button').on('click', this.onClick, this);
679 if(this.removeClass){
680 this.el.on('click', this.onClick, this);
683 this.el.enableDisplayMode();
686 onClick : function(e)
692 Roo.log('button on click ');
693 if(this.preventDefault){
696 if (this.pressed === true || this.pressed === false) {
697 this.pressed = !this.pressed;
698 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699 this.fireEvent('toggle', this, e, this.pressed);
703 this.fireEvent('click', this, e);
707 * Enables this button
711 this.disabled = false;
712 this.el.removeClass('disabled');
716 * Disable this button
720 this.disabled = true;
721 this.el.addClass('disabled');
724 * sets the active state on/off,
725 * @param {Boolean} state (optional) Force a particular state
727 setActive : function(v) {
729 this.el[v ? 'addClass' : 'removeClass']('active');
732 * toggles the current active state
734 toggleActive : function()
736 var active = this.el.hasClass('active');
737 this.setActive(!active);
741 setText : function(str)
743 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
747 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
770 * @class Roo.bootstrap.Column
771 * @extends Roo.bootstrap.Component
772 * Bootstrap Column class
773 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
775 * @cfg {Number} md colspan out of 12 for computer-sized screens
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
777 * @cfg {String} html content of column.
780 * Create a new Column
781 * @param {Object} config The config object
784 Roo.bootstrap.Column = function(config){
785 Roo.bootstrap.Column.superclass.constructor.call(this, config);
788 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
797 getAutoCreate : function(){
798 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
806 ['xs','sm','md','lg'].map(function(size){
807 if (settings[size]) {
808 cfg.cls += ' col-' + size + '-' + settings[size];
811 if (this.html.length) {
812 cfg.html = this.html;
831 * @class Roo.bootstrap.Container
832 * @extends Roo.bootstrap.Component
833 * Bootstrap Container class
834 * @cfg {Boolean} jumbotron is it a jumbotron element
835 * @cfg {String} html content of element
836 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
837 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
838 * @cfg {String} header content of header (for panel)
839 * @cfg {String} footer content of footer (for panel)
840 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
841 * @cfg {String} tag (header|aside|section) type of HTML tag.
845 * Create a new Container
846 * @param {Object} config The config object
849 Roo.bootstrap.Container = function(config){
850 Roo.bootstrap.Container.superclass.constructor.call(this, config);
853 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
864 getChildContainer : function() {
870 if (this.panel.length) {
871 return this.el.select('.panel-body',true).first();
878 getAutoCreate : function(){
881 tag : this.tag || 'div',
885 if (this.jumbotron) {
886 cfg.cls = 'jumbotron';
888 // - this is applied by the parent..
890 // cfg.cls = this.cls + '';
893 if (this.sticky.length) {
895 var bd = Roo.get(document.body);
896 if (!bd.hasClass('bootstrap-sticky')) {
897 bd.addClass('bootstrap-sticky');
898 Roo.select('html',true).setStyle('height', '100%');
901 cfg.cls += 'bootstrap-sticky-' + this.sticky;
905 if (this.well.length) {
909 cfg.cls +=' well well-' +this.well;
919 if (this.panel.length) {
920 cfg.cls += ' panel panel-' + this.panel;
922 if (this.header.length) {
925 cls : 'panel-heading',
941 if (this.footer.length) {
943 cls : 'panel-footer',
952 body.html = this.html || cfg.html;
954 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
955 cfg.cls = 'container';
963 if(!this.el || !this.panel.length || !this.header.length){
967 return this.el.select('.panel-title',true).first();
970 setTitle : function(v)
972 var titleEl = this.titleEl();
978 titleEl.dom.innerHTML = v;
981 getTitle : function()
984 var titleEl = this.titleEl();
990 return titleEl.dom.innerHTML;
1004 * @class Roo.bootstrap.Img
1005 * @extends Roo.bootstrap.Component
1006 * Bootstrap Img class
1007 * @cfg {Boolean} imgResponsive false | true
1008 * @cfg {String} border rounded | circle | thumbnail
1009 * @cfg {String} src image source
1010 * @cfg {String} alt image alternative text
1011 * @cfg {String} href a tag href
1012 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1015 * Create a new Input
1016 * @param {Object} config The config object
1019 Roo.bootstrap.Img = function(config){
1020 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1026 * The img click event for the img.
1027 * @param {Roo.EventObject} e
1033 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1035 imgResponsive: true,
1041 getAutoCreate : function(){
1045 cls: (this.imgResponsive) ? 'img-responsive' : '',
1049 cfg.html = this.html || cfg.html;
1051 cfg.src = this.src || cfg.src;
1053 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1054 cfg.cls += ' img-' + this.border;
1071 a.target = this.target;
1077 return (this.href) ? a : cfg;
1080 initEvents: function() {
1083 this.el.on('click', this.onClick, this);
1087 onClick : function(e)
1089 Roo.log('img onclick');
1090 this.fireEvent('click', this, e);
1104 * @class Roo.bootstrap.Link
1105 * @extends Roo.bootstrap.Component
1106 * Bootstrap Link Class
1107 * @cfg {String} alt image alternative text
1108 * @cfg {String} href a tag href
1109 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1110 * @cfg {String} html the content of the link.
1111 * @cfg {Boolean} preventDefault (true | false) default false
1115 * Create a new Input
1116 * @param {Object} config The config object
1119 Roo.bootstrap.Link = function(config){
1120 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1126 * The img click event for the img.
1127 * @param {Roo.EventObject} e
1133 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1137 preventDefault: false,
1139 getAutoCreate : function(){
1143 html : this.html || 'html-missing'
1150 cfg.href = this.href || '#';
1152 cfg.target = this.target;
1158 initEvents: function() {
1160 if(!this.href || this.preventDefault){
1161 this.el.on('click', this.onClick, this);
1165 onClick : function(e)
1167 if(this.preventDefault){
1170 //Roo.log('img onclick');
1171 this.fireEvent('click', this, e);
1184 * @class Roo.bootstrap.Header
1185 * @extends Roo.bootstrap.Component
1186 * Bootstrap Header class
1187 * @cfg {String} html content of header
1188 * @cfg {Number} level (1|2|3|4|5|6) default 1
1191 * Create a new Header
1192 * @param {Object} config The config object
1196 Roo.bootstrap.Header = function(config){
1197 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1200 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1208 getAutoCreate : function(){
1211 tag: 'h' + (1 *this.level),
1212 html: this.html || 'fill in html'
1224 * Ext JS Library 1.1.1
1225 * Copyright(c) 2006-2007, Ext JS, LLC.
1227 * Originally Released Under LGPL - original licence link has changed is not relivant.
1230 * <script type="text/javascript">
1234 * @class Roo.bootstrap.MenuMgr
1235 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1238 Roo.bootstrap.MenuMgr = function(){
1239 var menus, active, groups = {}, attached = false, lastShow = new Date();
1241 // private - called when first menu is created
1244 active = new Roo.util.MixedCollection();
1245 Roo.get(document).addKeyListener(27, function(){
1246 if(active.length > 0){
1254 if(active && active.length > 0){
1255 var c = active.clone();
1265 if(active.length < 1){
1266 Roo.get(document).un("mouseup", onMouseDown);
1274 var last = active.last();
1275 lastShow = new Date();
1278 Roo.get(document).on("mouseup", onMouseDown);
1283 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1284 m.parentMenu.activeChild = m;
1285 }else if(last && last.isVisible()){
1286 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1291 function onBeforeHide(m){
1293 m.activeChild.hide();
1295 if(m.autoHideTimer){
1296 clearTimeout(m.autoHideTimer);
1297 delete m.autoHideTimer;
1302 function onBeforeShow(m){
1303 var pm = m.parentMenu;
1304 if(!pm && !m.allowOtherMenus){
1306 }else if(pm && pm.activeChild && active != m){
1307 pm.activeChild.hide();
1312 function onMouseDown(e){
1313 Roo.log("on MouseDown");
1314 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1322 function onBeforeCheck(mi, state){
1324 var g = groups[mi.group];
1325 for(var i = 0, l = g.length; i < l; i++){
1327 g[i].setChecked(false);
1336 * Hides all menus that are currently visible
1338 hideAll : function(){
1343 register : function(menu){
1347 menus[menu.id] = menu;
1348 menu.on("beforehide", onBeforeHide);
1349 menu.on("hide", onHide);
1350 menu.on("beforeshow", onBeforeShow);
1351 menu.on("show", onShow);
1353 if(g && menu.events["checkchange"]){
1357 groups[g].push(menu);
1358 menu.on("checkchange", onCheck);
1363 * Returns a {@link Roo.menu.Menu} object
1364 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1365 * be used to generate and return a new Menu instance.
1367 get : function(menu){
1368 if(typeof menu == "string"){ // menu id
1370 }else if(menu.events){ // menu instance
1373 /*else if(typeof menu.length == 'number'){ // array of menu items?
1374 return new Roo.bootstrap.Menu({items:menu});
1375 }else{ // otherwise, must be a config
1376 return new Roo.bootstrap.Menu(menu);
1383 unregister : function(menu){
1384 delete menus[menu.id];
1385 menu.un("beforehide", onBeforeHide);
1386 menu.un("hide", onHide);
1387 menu.un("beforeshow", onBeforeShow);
1388 menu.un("show", onShow);
1390 if(g && menu.events["checkchange"]){
1391 groups[g].remove(menu);
1392 menu.un("checkchange", onCheck);
1397 registerCheckable : function(menuItem){
1398 var g = menuItem.group;
1403 groups[g].push(menuItem);
1404 menuItem.on("beforecheckchange", onBeforeCheck);
1409 unregisterCheckable : function(menuItem){
1410 var g = menuItem.group;
1412 groups[g].remove(menuItem);
1413 menuItem.un("beforecheckchange", onBeforeCheck);
1425 * @class Roo.bootstrap.Menu
1426 * @extends Roo.bootstrap.Component
1427 * Bootstrap Menu class - container for MenuItems
1428 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1432 * @param {Object} config The config object
1436 Roo.bootstrap.Menu = function(config){
1437 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1438 if (this.registerMenu) {
1439 Roo.bootstrap.MenuMgr.register(this);
1444 * Fires before this menu is displayed
1445 * @param {Roo.menu.Menu} this
1450 * Fires before this menu is hidden
1451 * @param {Roo.menu.Menu} this
1456 * Fires after this menu is displayed
1457 * @param {Roo.menu.Menu} this
1462 * Fires after this menu is hidden
1463 * @param {Roo.menu.Menu} this
1468 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1469 * @param {Roo.menu.Menu} this
1470 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1471 * @param {Roo.EventObject} e
1476 * Fires when the mouse is hovering over this menu
1477 * @param {Roo.menu.Menu} this
1478 * @param {Roo.EventObject} e
1479 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1484 * Fires when the mouse exits this menu
1485 * @param {Roo.menu.Menu} this
1486 * @param {Roo.EventObject} e
1487 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1492 * Fires when a menu item contained in this menu is clicked
1493 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1494 * @param {Roo.EventObject} e
1498 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1501 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1505 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1508 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1510 registerMenu : true,
1512 menuItems :false, // stores the menu items..
1518 getChildContainer : function() {
1522 getAutoCreate : function(){
1524 //if (['right'].indexOf(this.align)!==-1) {
1525 // cfg.cn[1].cls += ' pull-right'
1531 cls : 'dropdown-menu' ,
1532 style : 'z-index:1000'
1536 if (this.type === 'submenu') {
1537 cfg.cls = 'submenu active';
1539 if (this.type === 'treeview') {
1540 cfg.cls = 'treeview-menu';
1545 initEvents : function() {
1547 // Roo.log("ADD event");
1548 // Roo.log(this.triggerEl.dom);
1549 this.triggerEl.on('click', this.onTriggerPress, this);
1550 this.triggerEl.addClass('dropdown-toggle');
1551 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1553 this.el.on("mouseover", this.onMouseOver, this);
1554 this.el.on("mouseout", this.onMouseOut, this);
1558 findTargetItem : function(e){
1559 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1563 //Roo.log(t); Roo.log(t.id);
1565 //Roo.log(this.menuitems);
1566 return this.menuitems.get(t.id);
1568 //return this.items.get(t.menuItemId);
1573 onClick : function(e){
1574 Roo.log("menu.onClick");
1575 var t = this.findTargetItem(e);
1581 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1582 if(t == this.activeItem && t.shouldDeactivate(e)){
1583 this.activeItem.deactivate();
1584 delete this.activeItem;
1588 this.setActiveItem(t, true);
1595 Roo.log('pass click event');
1599 this.fireEvent("click", this, t, e);
1603 onMouseOver : function(e){
1604 var t = this.findTargetItem(e);
1607 // if(t.canActivate && !t.disabled){
1608 // this.setActiveItem(t, true);
1612 this.fireEvent("mouseover", this, e, t);
1614 isVisible : function(){
1615 return !this.hidden;
1617 onMouseOut : function(e){
1618 var t = this.findTargetItem(e);
1621 // if(t == this.activeItem && t.shouldDeactivate(e)){
1622 // this.activeItem.deactivate();
1623 // delete this.activeItem;
1626 this.fireEvent("mouseout", this, e, t);
1631 * Displays this menu relative to another element
1632 * @param {String/HTMLElement/Roo.Element} element The element to align to
1633 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1634 * the element (defaults to this.defaultAlign)
1635 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1637 show : function(el, pos, parentMenu){
1638 this.parentMenu = parentMenu;
1642 this.fireEvent("beforeshow", this);
1643 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1646 * Displays this menu at a specific xy position
1647 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1648 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1650 showAt : function(xy, parentMenu, /* private: */_e){
1651 this.parentMenu = parentMenu;
1656 this.fireEvent("beforeshow", this);
1658 //xy = this.el.adjustForConstraints(xy);
1660 //this.el.setXY(xy);
1662 this.hideMenuItems();
1663 this.hidden = false;
1664 this.triggerEl.addClass('open');
1666 this.fireEvent("show", this);
1672 this.doFocus.defer(50, this);
1676 doFocus : function(){
1678 this.focusEl.focus();
1683 * Hides this menu and optionally all parent menus
1684 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1686 hide : function(deep){
1688 this.hideMenuItems();
1689 if(this.el && this.isVisible()){
1690 this.fireEvent("beforehide", this);
1691 if(this.activeItem){
1692 this.activeItem.deactivate();
1693 this.activeItem = null;
1695 this.triggerEl.removeClass('open');;
1697 this.fireEvent("hide", this);
1699 if(deep === true && this.parentMenu){
1700 this.parentMenu.hide(true);
1704 onTriggerPress : function(e)
1707 Roo.log('trigger press');
1708 //Roo.log(e.getTarget());
1709 // Roo.log(this.triggerEl.dom);
1710 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1713 if (this.isVisible()) {
1717 this.show(this.triggerEl, false, false);
1726 hideMenuItems : function()
1728 //$(backdrop).remove()
1729 Roo.select('.open',true).each(function(aa) {
1731 aa.removeClass('open');
1732 //var parent = getParent($(this))
1733 //var relatedTarget = { relatedTarget: this }
1735 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1736 //if (e.isDefaultPrevented()) return
1737 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1740 addxtypeChild : function (tree, cntr) {
1741 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1743 this.menuitems.add(comp);
1764 * @class Roo.bootstrap.MenuItem
1765 * @extends Roo.bootstrap.Component
1766 * Bootstrap MenuItem class
1767 * @cfg {String} html the menu label
1768 * @cfg {String} href the link
1769 * @cfg {Boolean} preventDefault (true | false) default true
1773 * Create a new MenuItem
1774 * @param {Object} config The config object
1778 Roo.bootstrap.MenuItem = function(config){
1779 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1784 * The raw click event for the entire grid.
1785 * @param {Roo.EventObject} e
1791 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1795 preventDefault: true,
1797 getAutoCreate : function(){
1800 cls: 'dropdown-menu-item',
1809 if (this.parent().type == 'treeview') {
1810 cfg.cls = 'treeview-menu';
1813 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1814 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1818 initEvents: function() {
1820 //this.el.select('a').on('click', this.onClick, this);
1823 onClick : function(e)
1825 Roo.log('item on click ');
1826 //if(this.preventDefault){
1827 // e.preventDefault();
1829 //this.parent().hideMenuItems();
1831 this.fireEvent('click', this, e);
1850 * @class Roo.bootstrap.MenuSeparator
1851 * @extends Roo.bootstrap.Component
1852 * Bootstrap MenuSeparator class
1855 * Create a new MenuItem
1856 * @param {Object} config The config object
1860 Roo.bootstrap.MenuSeparator = function(config){
1861 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1864 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1866 getAutoCreate : function(){
1881 <div class="modal fade">
1882 <div class="modal-dialog">
1883 <div class="modal-content">
1884 <div class="modal-header">
1885 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1886 <h4 class="modal-title">Modal title</h4>
1888 <div class="modal-body">
1889 <p>One fine body…</p>
1891 <div class="modal-footer">
1892 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1893 <button type="button" class="btn btn-primary">Save changes</button>
1895 </div><!-- /.modal-content -->
1896 </div><!-- /.modal-dialog -->
1897 </div><!-- /.modal -->
1907 * @class Roo.bootstrap.Modal
1908 * @extends Roo.bootstrap.Component
1909 * Bootstrap Modal class
1910 * @cfg {String} title Title of dialog
1911 * @cfg {Boolean} specificTitle (true|false) default false
1912 * @cfg {Array} buttons Array of buttons or standard button set..
1913 * @cfg {String} buttonPosition (left|right|center) default right
1916 * Create a new Modal Dialog
1917 * @param {Object} config The config object
1920 Roo.bootstrap.Modal = function(config){
1921 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1926 * The raw btnclick event for the button
1927 * @param {Roo.EventObject} e
1931 this.buttons = this.buttons || [];
1934 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1936 title : 'test dialog',
1943 specificTitle: false,
1945 buttonPosition: 'right',
1947 onRender : function(ct, position)
1949 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1952 var cfg = Roo.apply({}, this.getAutoCreate());
1955 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1957 //if (!cfg.name.length) {
1961 cfg.cls += ' ' + this.cls;
1964 cfg.style = this.style;
1966 this.el = Roo.get(document.body).createChild(cfg, position);
1968 //var type = this.el.dom.type;
1970 if(this.tabIndex !== undefined){
1971 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1976 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1977 this.maskEl.enableDisplayMode("block");
1979 //this.el.addClass("x-dlg-modal");
1981 if (this.buttons.length) {
1982 Roo.each(this.buttons, function(bb) {
1983 b = Roo.apply({}, bb);
1984 b.xns = b.xns || Roo.bootstrap;
1985 b.xtype = b.xtype || 'Button';
1986 if (typeof(b.listeners) == 'undefined') {
1987 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1990 var btn = Roo.factory(b);
1992 btn.onRender(this.el.select('.modal-footer div').first());
1996 // render the children.
1999 if(typeof(this.items) != 'undefined'){
2000 var items = this.items;
2003 for(var i =0;i < items.length;i++) {
2004 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2008 this.items = nitems;
2010 this.body = this.el.select('.modal-body',true).first();
2011 this.close = this.el.select('.modal-header .close', true).first();
2012 this.footer = this.el.select('.modal-footer',true).first();
2014 //this.el.addClass([this.fieldClass, this.cls]);
2017 getAutoCreate : function(){
2022 html : this.html || ''
2027 cls : 'modal-title',
2031 if(this.specificTitle){
2037 style : 'display: none',
2040 cls: "modal-dialog",
2043 cls : "modal-content",
2046 cls : 'modal-header',
2058 cls : 'modal-footer',
2062 cls: 'btn-' + this.buttonPosition
2081 getChildContainer : function() {
2083 return this.el.select('.modal-body',true).first();
2086 getButtonContainer : function() {
2087 return this.el.select('.modal-footer div',true).first();
2090 initEvents : function()
2092 this.el.select('.modal-header .close').on('click', this.hide, this);
2094 // this.addxtype(this);
2098 if (!this.rendered) {
2102 this.el.addClass('on');
2103 this.el.removeClass('fade');
2104 this.el.setStyle('display', 'block');
2105 Roo.get(document.body).addClass("x-body-masked");
2106 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2108 this.el.setStyle('zIndex', '10001');
2109 this.fireEvent('show', this);
2115 Roo.log('Modal hide?!');
2117 Roo.get(document.body).removeClass("x-body-masked");
2118 this.el.removeClass('on');
2119 this.el.addClass('fade');
2120 this.el.setStyle('display', 'none');
2121 this.fireEvent('hide', this);
2124 addButton : function(str, cb)
2128 var b = Roo.apply({}, { html : str } );
2129 b.xns = b.xns || Roo.bootstrap;
2130 b.xtype = b.xtype || 'Button';
2131 if (typeof(b.listeners) == 'undefined') {
2132 b.listeners = { click : cb.createDelegate(this) };
2135 var btn = Roo.factory(b);
2137 btn.onRender(this.el.select('.modal-footer div').first());
2143 setDefaultButton : function(btn)
2145 //this.el.select('.modal-footer').()
2147 resizeTo: function(w,h)
2151 setContentSize : function(w, h)
2155 onButtonClick: function(btn,e)
2158 this.fireEvent('btnclick', btn.name, e);
2160 setTitle: function(str) {
2161 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2167 Roo.apply(Roo.bootstrap.Modal, {
2169 * Button config that displays a single OK button
2178 * Button config that displays Yes and No buttons
2194 * Button config that displays OK and Cancel buttons
2209 * Button config that displays Yes, No and Cancel buttons
2231 * messagebox - can be used as a replace
2235 * @class Roo.MessageBox
2236 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2240 Roo.Msg.alert('Status', 'Changes saved successfully.');
2242 // Prompt for user data:
2243 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2245 // process text value...
2249 // Show a dialog using config options:
2251 title:'Save Changes?',
2252 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2253 buttons: Roo.Msg.YESNOCANCEL,
2260 Roo.bootstrap.MessageBox = function(){
2261 var dlg, opt, mask, waitTimer;
2262 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2263 var buttons, activeTextEl, bwidth;
2267 var handleButton = function(button){
2269 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2273 var handleHide = function(){
2275 dlg.el.removeClass(opt.cls);
2278 // Roo.TaskMgr.stop(waitTimer);
2279 // waitTimer = null;
2284 var updateButtons = function(b){
2287 buttons["ok"].hide();
2288 buttons["cancel"].hide();
2289 buttons["yes"].hide();
2290 buttons["no"].hide();
2291 //dlg.footer.dom.style.display = 'none';
2294 dlg.footer.dom.style.display = '';
2295 for(var k in buttons){
2296 if(typeof buttons[k] != "function"){
2299 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2300 width += buttons[k].el.getWidth()+15;
2310 var handleEsc = function(d, k, e){
2311 if(opt && opt.closable !== false){
2321 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2322 * @return {Roo.BasicDialog} The BasicDialog element
2324 getDialog : function(){
2326 dlg = new Roo.bootstrap.Modal( {
2329 //constraintoviewport:false,
2331 //collapsible : false,
2336 //buttonAlign:"center",
2337 closeClick : function(){
2338 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2341 handleButton("cancel");
2346 dlg.on("hide", handleHide);
2348 //dlg.addKeyListener(27, handleEsc);
2350 this.buttons = buttons;
2351 var bt = this.buttonText;
2352 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2353 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2354 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2355 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2357 bodyEl = dlg.body.createChild({
2359 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2360 '<textarea class="roo-mb-textarea"></textarea>' +
2361 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2363 msgEl = bodyEl.dom.firstChild;
2364 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2365 textboxEl.enableDisplayMode();
2366 textboxEl.addKeyListener([10,13], function(){
2367 if(dlg.isVisible() && opt && opt.buttons){
2370 }else if(opt.buttons.yes){
2371 handleButton("yes");
2375 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2376 textareaEl.enableDisplayMode();
2377 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2378 progressEl.enableDisplayMode();
2379 var pf = progressEl.dom.firstChild;
2381 pp = Roo.get(pf.firstChild);
2382 pp.setHeight(pf.offsetHeight);
2390 * Updates the message box body text
2391 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2392 * the XHTML-compliant non-breaking space character '&#160;')
2393 * @return {Roo.MessageBox} This message box
2395 updateText : function(text){
2396 if(!dlg.isVisible() && !opt.width){
2397 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2399 msgEl.innerHTML = text || ' ';
2401 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2402 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2404 Math.min(opt.width || cw , this.maxWidth),
2405 Math.max(opt.minWidth || this.minWidth, bwidth)
2408 activeTextEl.setWidth(w);
2410 if(dlg.isVisible()){
2411 dlg.fixedcenter = false;
2413 // to big, make it scroll. = But as usual stupid IE does not support
2416 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2417 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2418 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2420 bodyEl.dom.style.height = '';
2421 bodyEl.dom.style.overflowY = '';
2424 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2426 bodyEl.dom.style.overflowX = '';
2429 dlg.setContentSize(w, bodyEl.getHeight());
2430 if(dlg.isVisible()){
2431 dlg.fixedcenter = true;
2437 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2438 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2439 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2440 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2441 * @return {Roo.MessageBox} This message box
2443 updateProgress : function(value, text){
2445 this.updateText(text);
2447 if (pp) { // weird bug on my firefox - for some reason this is not defined
2448 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2454 * Returns true if the message box is currently displayed
2455 * @return {Boolean} True if the message box is visible, else false
2457 isVisible : function(){
2458 return dlg && dlg.isVisible();
2462 * Hides the message box if it is displayed
2465 if(this.isVisible()){
2471 * Displays a new message box, or reinitializes an existing message box, based on the config options
2472 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2473 * The following config object properties are supported:
2475 Property Type Description
2476 ---------- --------------- ------------------------------------------------------------------------------------
2477 animEl String/Element An id or Element from which the message box should animate as it opens and
2478 closes (defaults to undefined)
2479 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2480 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2481 closable Boolean False to hide the top-right close button (defaults to true). Note that
2482 progress and wait dialogs will ignore this property and always hide the
2483 close button as they can only be closed programmatically.
2484 cls String A custom CSS class to apply to the message box element
2485 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2486 displayed (defaults to 75)
2487 fn Function A callback function to execute after closing the dialog. The arguments to the
2488 function will be btn (the name of the button that was clicked, if applicable,
2489 e.g. "ok"), and text (the value of the active text field, if applicable).
2490 Progress and wait dialogs will ignore this option since they do not respond to
2491 user actions and can only be closed programmatically, so any required function
2492 should be called by the same code after it closes the dialog.
2493 icon String A CSS class that provides a background image to be used as an icon for
2494 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2495 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2496 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2497 modal Boolean False to allow user interaction with the page while the message box is
2498 displayed (defaults to true)
2499 msg String A string that will replace the existing message box body text (defaults
2500 to the XHTML-compliant non-breaking space character ' ')
2501 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2502 progress Boolean True to display a progress bar (defaults to false)
2503 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2504 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2505 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2506 title String The title text
2507 value String The string value to set into the active textbox element if displayed
2508 wait Boolean True to display a progress bar (defaults to false)
2509 width Number The width of the dialog in pixels
2516 msg: 'Please enter your address:',
2518 buttons: Roo.MessageBox.OKCANCEL,
2521 animEl: 'addAddressBtn'
2524 * @param {Object} config Configuration options
2525 * @return {Roo.MessageBox} This message box
2527 show : function(options)
2530 // this causes nightmares if you show one dialog after another
2531 // especially on callbacks..
2533 if(this.isVisible()){
2536 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2537 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2538 Roo.log("New Dialog Message:" + options.msg )
2539 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2540 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2543 var d = this.getDialog();
2545 d.setTitle(opt.title || " ");
2546 d.close.setDisplayed(opt.closable !== false);
2547 activeTextEl = textboxEl;
2548 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2553 textareaEl.setHeight(typeof opt.multiline == "number" ?
2554 opt.multiline : this.defaultTextHeight);
2555 activeTextEl = textareaEl;
2564 progressEl.setDisplayed(opt.progress === true);
2565 this.updateProgress(0);
2566 activeTextEl.dom.value = opt.value || "";
2568 dlg.setDefaultButton(activeTextEl);
2570 var bs = opt.buttons;
2574 }else if(bs && bs.yes){
2575 db = buttons["yes"];
2577 dlg.setDefaultButton(db);
2579 bwidth = updateButtons(opt.buttons);
2580 this.updateText(opt.msg);
2582 d.el.addClass(opt.cls);
2584 d.proxyDrag = opt.proxyDrag === true;
2585 d.modal = opt.modal !== false;
2586 d.mask = opt.modal !== false ? mask : false;
2588 // force it to the end of the z-index stack so it gets a cursor in FF
2589 document.body.appendChild(dlg.el.dom);
2590 d.animateTarget = null;
2591 d.show(options.animEl);
2597 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2598 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2599 * and closing the message box when the process is complete.
2600 * @param {String} title The title bar text
2601 * @param {String} msg The message box body text
2602 * @return {Roo.MessageBox} This message box
2604 progress : function(title, msg){
2611 minWidth: this.minProgressWidth,
2618 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2619 * If a callback function is passed it will be called after the user clicks the button, and the
2620 * id of the button that was clicked will be passed as the only parameter to the callback
2621 * (could also be the top-right close button).
2622 * @param {String} title The title bar text
2623 * @param {String} msg The message box body text
2624 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2625 * @param {Object} scope (optional) The scope of the callback function
2626 * @return {Roo.MessageBox} This message box
2628 alert : function(title, msg, fn, scope){
2641 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2642 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2643 * You are responsible for closing the message box when the process is complete.
2644 * @param {String} msg The message box body text
2645 * @param {String} title (optional) The title bar text
2646 * @return {Roo.MessageBox} This message box
2648 wait : function(msg, title){
2659 waitTimer = Roo.TaskMgr.start({
2661 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2669 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2670 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2671 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2672 * @param {String} title The title bar text
2673 * @param {String} msg The message box body text
2674 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2675 * @param {Object} scope (optional) The scope of the callback function
2676 * @return {Roo.MessageBox} This message box
2678 confirm : function(title, msg, fn, scope){
2682 buttons: this.YESNO,
2691 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2692 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2693 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2694 * (could also be the top-right close button) and the text that was entered will be passed as the two
2695 * parameters to the callback.
2696 * @param {String} title The title bar text
2697 * @param {String} msg The message box body text
2698 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2699 * @param {Object} scope (optional) The scope of the callback function
2700 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2701 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2702 * @return {Roo.MessageBox} This message box
2704 prompt : function(title, msg, fn, scope, multiline){
2708 buttons: this.OKCANCEL,
2713 multiline: multiline,
2720 * Button config that displays a single OK button
2725 * Button config that displays Yes and No buttons
2728 YESNO : {yes:true, no:true},
2730 * Button config that displays OK and Cancel buttons
2733 OKCANCEL : {ok:true, cancel:true},
2735 * Button config that displays Yes, No and Cancel buttons
2738 YESNOCANCEL : {yes:true, no:true, cancel:true},
2741 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2744 defaultTextHeight : 75,
2746 * The maximum width in pixels of the message box (defaults to 600)
2751 * The minimum width in pixels of the message box (defaults to 100)
2756 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2757 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2760 minProgressWidth : 250,
2762 * An object containing the default button text strings that can be overriden for localized language support.
2763 * Supported properties are: ok, cancel, yes and no.
2764 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2777 * Shorthand for {@link Roo.MessageBox}
2779 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2780 Roo.Msg = Roo.Msg || Roo.MessageBox;
2789 * @class Roo.bootstrap.Navbar
2790 * @extends Roo.bootstrap.Component
2791 * Bootstrap Navbar class
2794 * Create a new Navbar
2795 * @param {Object} config The config object
2799 Roo.bootstrap.Navbar = function(config){
2800 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2804 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2813 getAutoCreate : function(){
2816 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2820 initEvents :function ()
2822 //Roo.log(this.el.select('.navbar-toggle',true));
2823 this.el.select('.navbar-toggle',true).on('click', function() {
2824 // Roo.log('click');
2825 this.el.select('.navbar-collapse',true).toggleClass('in');
2833 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2835 var size = this.el.getSize();
2836 this.maskEl.setSize(size.width, size.height);
2837 this.maskEl.enableDisplayMode("block");
2846 getChildContainer : function()
2848 if (this.el.select('.collapse').getCount()) {
2849 return this.el.select('.collapse',true).first();
2882 * @class Roo.bootstrap.NavSimplebar
2883 * @extends Roo.bootstrap.Navbar
2884 * Bootstrap Sidebar class
2886 * @cfg {Boolean} inverse is inverted color
2888 * @cfg {String} type (nav | pills | tabs)
2889 * @cfg {Boolean} arrangement stacked | justified
2890 * @cfg {String} align (left | right) alignment
2892 * @cfg {Boolean} main (true|false) main nav bar? default false
2893 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2895 * @cfg {String} tag (header|footer|nav|div) default is nav
2901 * Create a new Sidebar
2902 * @param {Object} config The config object
2906 Roo.bootstrap.NavSimplebar = function(config){
2907 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2910 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2926 getAutoCreate : function(){
2930 tag : this.tag || 'div',
2943 this.type = this.type || 'nav';
2944 if (['tabs','pills'].indexOf(this.type)!==-1) {
2945 cfg.cn[0].cls += ' nav-' + this.type
2949 if (this.type!=='nav') {
2950 Roo.log('nav type must be nav/tabs/pills')
2952 cfg.cn[0].cls += ' navbar-nav'
2958 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2959 cfg.cn[0].cls += ' nav-' + this.arrangement;
2963 if (this.align === 'right') {
2964 cfg.cn[0].cls += ' navbar-right';
2968 cfg.cls += ' navbar-inverse';
2995 * @class Roo.bootstrap.NavHeaderbar
2996 * @extends Roo.bootstrap.NavSimplebar
2997 * Bootstrap Sidebar class
2999 * @cfg {String} brand what is brand
3000 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3001 * @cfg {String} brand_href href of the brand
3002 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3005 * Create a new Sidebar
3006 * @param {Object} config The config object
3010 Roo.bootstrap.NavHeaderbar = function(config){
3011 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3014 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3022 getAutoCreate : function(){
3025 tag: this.nav || 'nav',
3034 cls: 'navbar-header',
3039 cls: 'navbar-toggle',
3040 'data-toggle': 'collapse',
3045 html: 'Toggle navigation'
3067 cls: 'collapse navbar-collapse',
3071 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3073 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3074 cfg.cls += ' navbar-' + this.position;
3076 // tag can override this..
3078 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3081 if (this.brand !== '') {
3084 href: this.brand_href ? this.brand_href : '#',
3085 cls: 'navbar-brand',
3093 cfg.cls += ' main-nav';
3118 * @class Roo.bootstrap.NavSidebar
3119 * @extends Roo.bootstrap.Navbar
3120 * Bootstrap Sidebar class
3123 * Create a new Sidebar
3124 * @param {Object} config The config object
3128 Roo.bootstrap.NavSidebar = function(config){
3129 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3132 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3134 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3136 getAutoCreate : function(){
3141 cls: 'sidebar sidebar-nav'
3163 * @class Roo.bootstrap.NavGroup
3164 * @extends Roo.bootstrap.Component
3165 * Bootstrap NavGroup class
3166 * @cfg {String} align left | right
3167 * @cfg {Boolean} inverse false | true
3168 * @cfg {String} type (nav|pills|tab) default nav
3169 * @cfg {String} navId - reference Id for navbar.
3173 * Create a new nav group
3174 * @param {Object} config The config object
3177 Roo.bootstrap.NavGroup = function(config){
3178 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3181 Roo.bootstrap.NavGroup.register(this);
3185 * Fires when the active item changes
3186 * @param {Roo.bootstrap.NavGroup} this
3187 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3188 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3195 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3206 getAutoCreate : function()
3208 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3215 if (['tabs','pills'].indexOf(this.type)!==-1) {
3216 cfg.cls += ' nav-' + this.type
3218 if (this.type!=='nav') {
3219 Roo.log('nav type must be nav/tabs/pills')
3221 cfg.cls += ' navbar-nav'
3224 if (this.parent().sidebar) {
3227 cls: 'dashboard-menu sidebar-menu'
3233 if (this.form === true) {
3239 if (this.align === 'right') {
3240 cfg.cls += ' navbar-right';
3242 cfg.cls += ' navbar-left';
3246 if (this.align === 'right') {
3247 cfg.cls += ' navbar-right';
3251 cfg.cls += ' navbar-inverse';
3259 * sets the active Navigation item
3260 * @param {Roo.bootstrap.NavItem} the new current navitem
3262 setActiveItem : function(item)
3265 Roo.each(this.navItems, function(v){
3270 v.setActive(false, true);
3277 item.setActive(true, true);
3278 this.fireEvent('changed', this, item, prev);
3283 * gets the active Navigation item
3284 * @return {Roo.bootstrap.NavItem} the current navitem
3286 getActive : function()
3290 Roo.each(this.navItems, function(v){
3301 indexOfNav : function()
3305 Roo.each(this.navItems, function(v,i){
3316 * adds a Navigation item
3317 * @param {Roo.bootstrap.NavItem} the navitem to add
3319 addItem : function(cfg)
3321 var cn = new Roo.bootstrap.NavItem(cfg);
3323 cn.parentId = this.id;
3324 cn.onRender(this.el, null);
3328 * register a Navigation item
3329 * @param {Roo.bootstrap.NavItem} the navitem to add
3331 register : function(item)
3333 this.navItems.push( item);
3334 item.navId = this.navId;
3339 getNavItem: function(tabId)
3342 Roo.each(this.navItems, function(e) {
3343 if (e.tabId == tabId) {
3353 setActiveNext : function()
3355 var i = this.indexOfNav(this.getActive());
3356 if (i > this.navItems.length) {
3359 this.setActiveItem(this.navItems[i+1]);
3361 setActivePrev : function()
3363 var i = this.indexOfNav(this.getActive());
3367 this.setActiveItem(this.navItems[i-1]);
3369 clearWasActive : function(except) {
3370 Roo.each(this.navItems, function(e) {
3371 if (e.tabId != except.tabId && e.was_active) {
3372 e.was_active = false;
3379 getWasActive : function ()
3382 Roo.each(this.navItems, function(e) {
3397 Roo.apply(Roo.bootstrap.NavGroup, {
3401 * register a Navigation Group
3402 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3404 register : function(navgrp)
3406 this.groups[navgrp.navId] = navgrp;
3410 * fetch a Navigation Group based on the navigation ID
3411 * @param {string} the navgroup to add
3412 * @returns {Roo.bootstrap.NavGroup} the navgroup
3414 get: function(navId) {
3415 if (typeof(this.groups[navId]) == 'undefined') {
3417 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3419 return this.groups[navId] ;
3434 * @class Roo.bootstrap.NavItem
3435 * @extends Roo.bootstrap.Component
3436 * Bootstrap Navbar.NavItem class
3437 * @cfg {String} href link to
3438 * @cfg {String} html content of button
3439 * @cfg {String} badge text inside badge
3440 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3441 * @cfg {String} glyphicon name of glyphicon
3442 * @cfg {String} icon name of font awesome icon
3443 * @cfg {Boolean} active Is item active
3444 * @cfg {Boolean} disabled Is item disabled
3446 * @cfg {Boolean} preventDefault (true | false) default false
3447 * @cfg {String} tabId the tab that this item activates.
3448 * @cfg {String} tagtype (a|span) render as a href or span?
3451 * Create a new Navbar Item
3452 * @param {Object} config The config object
3454 Roo.bootstrap.NavItem = function(config){
3455 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3460 * The raw click event for the entire grid.
3461 * @param {Roo.EventObject} e
3466 * Fires when the active item active state changes
3467 * @param {Roo.bootstrap.NavItem} this
3468 * @param {boolean} state the new state
3476 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3484 preventDefault : false,
3491 getAutoCreate : function(){
3499 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3501 if (this.disabled) {
3502 cfg.cls += ' disabled';
3505 if (this.href || this.html || this.glyphicon || this.icon) {
3509 href : this.href || "#",
3510 html: this.html || ''
3515 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3518 if(this.glyphicon) {
3519 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3524 cfg.cn[0].html += " <span class='caret'></span>";
3528 if (this.badge !== '') {
3530 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3538 initEvents: function() {
3539 // Roo.log('init events?');
3540 // Roo.log(this.el.dom);
3541 if (typeof (this.menu) != 'undefined') {
3542 this.menu.parentType = this.xtype;
3543 this.menu.triggerEl = this.el;
3544 this.addxtype(Roo.apply({}, this.menu));
3548 this.el.select('a',true).on('click', this.onClick, this);
3549 // at this point parent should be available..
3550 this.parent().register(this);
3553 onClick : function(e)
3556 if(this.preventDefault){
3559 if (this.disabled) {
3563 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3564 if (tg && tg.transition) {
3565 Roo.log("waiting for the transitionend");
3569 Roo.log("fire event clicked");
3570 if(this.fireEvent('click', this, e) === false){
3574 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3575 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3576 this.parent().setActiveItem(this);
3581 isActive: function () {
3584 setActive : function(state, fire, is_was_active)
3586 if (this.active && !state & this.navId) {
3587 this.was_active = true;
3588 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3590 nv.clearWasActive(this);
3594 this.active = state;
3597 this.el.removeClass('active');
3598 } else if (!this.el.hasClass('active')) {
3599 this.el.addClass('active');
3602 this.fireEvent('changed', this, state);
3605 // show a panel if it's registered and related..
3607 if (!this.navId || !this.tabId || !state || is_was_active) {
3611 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3615 var pan = tg.getPanelByName(this.tabId);
3619 // if we can not flip to new panel - go back to old nav highlight..
3620 if (false == tg.showPanel(pan)) {
3621 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3623 var onav = nv.getWasActive();
3625 onav.setActive(true, false, true);
3634 // this should not be here...
3635 setDisabled : function(state)
3637 this.disabled = state;
3639 this.el.removeClass('disabled');
3640 } else if (!this.el.hasClass('disabled')) {
3641 this.el.addClass('disabled');
3654 * <span> icon </span>
3655 * <span> text </span>
3656 * <span>badge </span>
3660 * @class Roo.bootstrap.NavSidebarItem
3661 * @extends Roo.bootstrap.NavItem
3662 * Bootstrap Navbar.NavSidebarItem class
3664 * Create a new Navbar Button
3665 * @param {Object} config The config object
3667 Roo.bootstrap.NavSidebarItem = function(config){
3668 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3673 * The raw click event for the entire grid.
3674 * @param {Roo.EventObject} e
3679 * Fires when the active item active state changes
3680 * @param {Roo.bootstrap.NavSidebarItem} this
3681 * @param {boolean} state the new state
3689 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3692 getAutoCreate : function(){
3697 href : this.href || '#',
3709 html : this.html || ''
3714 cfg.cls += ' active';
3718 if (this.glyphicon || this.icon) {
3719 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3720 a.cn.push({ tag : 'i', cls : c }) ;
3725 if (this.badge !== '') {
3726 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3730 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3731 a.cls += 'dropdown-toggle treeview' ;
3755 * @class Roo.bootstrap.Row
3756 * @extends Roo.bootstrap.Component
3757 * Bootstrap Row class (contains columns...)
3761 * @param {Object} config The config object
3764 Roo.bootstrap.Row = function(config){
3765 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3768 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3770 getAutoCreate : function(){
3789 * @class Roo.bootstrap.Element
3790 * @extends Roo.bootstrap.Component
3791 * Bootstrap Element class
3792 * @cfg {String} html contents of the element
3793 * @cfg {String} tag tag of the element
3794 * @cfg {String} cls class of the element
3797 * Create a new Element
3798 * @param {Object} config The config object
3801 Roo.bootstrap.Element = function(config){
3802 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3805 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3812 getAutoCreate : function(){
3837 * @class Roo.bootstrap.Pagination
3838 * @extends Roo.bootstrap.Component
3839 * Bootstrap Pagination class
3840 * @cfg {String} size xs | sm | md | lg
3841 * @cfg {Boolean} inverse false | true
3844 * Create a new Pagination
3845 * @param {Object} config The config object
3848 Roo.bootstrap.Pagination = function(config){
3849 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3852 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3858 getAutoCreate : function(){
3864 cfg.cls += ' inverse';
3870 cfg.cls += " " + this.cls;
3888 * @class Roo.bootstrap.PaginationItem
3889 * @extends Roo.bootstrap.Component
3890 * Bootstrap PaginationItem class
3891 * @cfg {String} html text
3892 * @cfg {String} href the link
3893 * @cfg {Boolean} preventDefault (true | false) default true
3894 * @cfg {Boolean} active (true | false) default false
3898 * Create a new PaginationItem
3899 * @param {Object} config The config object
3903 Roo.bootstrap.PaginationItem = function(config){
3904 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3909 * The raw click event for the entire grid.
3910 * @param {Roo.EventObject} e
3916 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3920 preventDefault: true,
3924 getAutoCreate : function(){
3930 href : this.href ? this.href : '#',
3931 html : this.html ? this.html : ''
3941 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3947 initEvents: function() {
3949 this.el.on('click', this.onClick, this);
3952 onClick : function(e)
3954 Roo.log('PaginationItem on click ');
3955 if(this.preventDefault){
3959 this.fireEvent('click', this, e);
3975 * @class Roo.bootstrap.Slider
3976 * @extends Roo.bootstrap.Component
3977 * Bootstrap Slider class
3980 * Create a new Slider
3981 * @param {Object} config The config object
3984 Roo.bootstrap.Slider = function(config){
3985 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3988 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3990 getAutoCreate : function(){
3994 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3998 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4010 * Ext JS Library 1.1.1
4011 * Copyright(c) 2006-2007, Ext JS, LLC.
4013 * Originally Released Under LGPL - original licence link has changed is not relivant.
4016 * <script type="text/javascript">
4021 * @class Roo.grid.ColumnModel
4022 * @extends Roo.util.Observable
4023 * This is the default implementation of a ColumnModel used by the Grid. It defines
4024 * the columns in the grid.
4027 var colModel = new Roo.grid.ColumnModel([
4028 {header: "Ticker", width: 60, sortable: true, locked: true},
4029 {header: "Company Name", width: 150, sortable: true},
4030 {header: "Market Cap.", width: 100, sortable: true},
4031 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4032 {header: "Employees", width: 100, sortable: true, resizable: false}
4037 * The config options listed for this class are options which may appear in each
4038 * individual column definition.
4039 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4041 * @param {Object} config An Array of column config objects. See this class's
4042 * config objects for details.
4044 Roo.grid.ColumnModel = function(config){
4046 * The config passed into the constructor
4048 this.config = config;
4051 // if no id, create one
4052 // if the column does not have a dataIndex mapping,
4053 // map it to the order it is in the config
4054 for(var i = 0, len = config.length; i < len; i++){
4056 if(typeof c.dataIndex == "undefined"){
4059 if(typeof c.renderer == "string"){
4060 c.renderer = Roo.util.Format[c.renderer];
4062 if(typeof c.id == "undefined"){
4065 if(c.editor && c.editor.xtype){
4066 c.editor = Roo.factory(c.editor, Roo.grid);
4068 if(c.editor && c.editor.isFormField){
4069 c.editor = new Roo.grid.GridEditor(c.editor);
4071 this.lookup[c.id] = c;
4075 * The width of columns which have no width specified (defaults to 100)
4078 this.defaultWidth = 100;
4081 * Default sortable of columns which have no sortable specified (defaults to false)
4084 this.defaultSortable = false;
4088 * @event widthchange
4089 * Fires when the width of a column changes.
4090 * @param {ColumnModel} this
4091 * @param {Number} columnIndex The column index
4092 * @param {Number} newWidth The new width
4094 "widthchange": true,
4096 * @event headerchange
4097 * Fires when the text of a header changes.
4098 * @param {ColumnModel} this
4099 * @param {Number} columnIndex The column index
4100 * @param {Number} newText The new header text
4102 "headerchange": true,
4104 * @event hiddenchange
4105 * Fires when a column is hidden or "unhidden".
4106 * @param {ColumnModel} this
4107 * @param {Number} columnIndex The column index
4108 * @param {Boolean} hidden true if hidden, false otherwise
4110 "hiddenchange": true,
4112 * @event columnmoved
4113 * Fires when a column is moved.
4114 * @param {ColumnModel} this
4115 * @param {Number} oldIndex
4116 * @param {Number} newIndex
4118 "columnmoved" : true,
4120 * @event columlockchange
4121 * Fires when a column's locked state is changed
4122 * @param {ColumnModel} this
4123 * @param {Number} colIndex
4124 * @param {Boolean} locked true if locked
4126 "columnlockchange" : true
4128 Roo.grid.ColumnModel.superclass.constructor.call(this);
4130 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4132 * @cfg {String} header The header text to display in the Grid view.
4135 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4136 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4137 * specified, the column's index is used as an index into the Record's data Array.
4140 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4141 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4144 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4145 * Defaults to the value of the {@link #defaultSortable} property.
4146 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4149 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4152 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4155 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4158 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4161 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4162 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4163 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4164 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4167 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4170 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4174 * Returns the id of the column at the specified index.
4175 * @param {Number} index The column index
4176 * @return {String} the id
4178 getColumnId : function(index){
4179 return this.config[index].id;
4183 * Returns the column for a specified id.
4184 * @param {String} id The column id
4185 * @return {Object} the column
4187 getColumnById : function(id){
4188 return this.lookup[id];
4193 * Returns the column for a specified dataIndex.
4194 * @param {String} dataIndex The column dataIndex
4195 * @return {Object|Boolean} the column or false if not found
4197 getColumnByDataIndex: function(dataIndex){
4198 var index = this.findColumnIndex(dataIndex);
4199 return index > -1 ? this.config[index] : false;
4203 * Returns the index for a specified column id.
4204 * @param {String} id The column id
4205 * @return {Number} the index, or -1 if not found
4207 getIndexById : function(id){
4208 for(var i = 0, len = this.config.length; i < len; i++){
4209 if(this.config[i].id == id){
4217 * Returns the index for a specified column dataIndex.
4218 * @param {String} dataIndex The column dataIndex
4219 * @return {Number} the index, or -1 if not found
4222 findColumnIndex : function(dataIndex){
4223 for(var i = 0, len = this.config.length; i < len; i++){
4224 if(this.config[i].dataIndex == dataIndex){
4232 moveColumn : function(oldIndex, newIndex){
4233 var c = this.config[oldIndex];
4234 this.config.splice(oldIndex, 1);
4235 this.config.splice(newIndex, 0, c);
4236 this.dataMap = null;
4237 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4240 isLocked : function(colIndex){
4241 return this.config[colIndex].locked === true;
4244 setLocked : function(colIndex, value, suppressEvent){
4245 if(this.isLocked(colIndex) == value){
4248 this.config[colIndex].locked = value;
4250 this.fireEvent("columnlockchange", this, colIndex, value);
4254 getTotalLockedWidth : function(){
4256 for(var i = 0; i < this.config.length; i++){
4257 if(this.isLocked(i) && !this.isHidden(i)){
4258 this.totalWidth += this.getColumnWidth(i);
4264 getLockedCount : function(){
4265 for(var i = 0, len = this.config.length; i < len; i++){
4266 if(!this.isLocked(i)){
4273 * Returns the number of columns.
4276 getColumnCount : function(visibleOnly){
4277 if(visibleOnly === true){
4279 for(var i = 0, len = this.config.length; i < len; i++){
4280 if(!this.isHidden(i)){
4286 return this.config.length;
4290 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4291 * @param {Function} fn
4292 * @param {Object} scope (optional)
4293 * @return {Array} result
4295 getColumnsBy : function(fn, scope){
4297 for(var i = 0, len = this.config.length; i < len; i++){
4298 var c = this.config[i];
4299 if(fn.call(scope||this, c, i) === true){
4307 * Returns true if the specified column is sortable.
4308 * @param {Number} col The column index
4311 isSortable : function(col){
4312 if(typeof this.config[col].sortable == "undefined"){
4313 return this.defaultSortable;
4315 return this.config[col].sortable;
4319 * Returns the rendering (formatting) function defined for the column.
4320 * @param {Number} col The column index.
4321 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4323 getRenderer : function(col){
4324 if(!this.config[col].renderer){
4325 return Roo.grid.ColumnModel.defaultRenderer;
4327 return this.config[col].renderer;
4331 * Sets the rendering (formatting) function for a column.
4332 * @param {Number} col The column index
4333 * @param {Function} fn The function to use to process the cell's raw data
4334 * to return HTML markup for the grid view. The render function is called with
4335 * the following parameters:<ul>
4336 * <li>Data value.</li>
4337 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4338 * <li>css A CSS style string to apply to the table cell.</li>
4339 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4340 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4341 * <li>Row index</li>
4342 * <li>Column index</li>
4343 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4345 setRenderer : function(col, fn){
4346 this.config[col].renderer = fn;
4350 * Returns the width for the specified column.
4351 * @param {Number} col The column index
4354 getColumnWidth : function(col){
4355 return this.config[col].width * 1 || this.defaultWidth;
4359 * Sets the width for a column.
4360 * @param {Number} col The column index
4361 * @param {Number} width The new width
4363 setColumnWidth : function(col, width, suppressEvent){
4364 this.config[col].width = width;
4365 this.totalWidth = null;
4367 this.fireEvent("widthchange", this, col, width);
4372 * Returns the total width of all columns.
4373 * @param {Boolean} includeHidden True to include hidden column widths
4376 getTotalWidth : function(includeHidden){
4377 if(!this.totalWidth){
4378 this.totalWidth = 0;
4379 for(var i = 0, len = this.config.length; i < len; i++){
4380 if(includeHidden || !this.isHidden(i)){
4381 this.totalWidth += this.getColumnWidth(i);
4385 return this.totalWidth;
4389 * Returns the header for the specified column.
4390 * @param {Number} col The column index
4393 getColumnHeader : function(col){
4394 return this.config[col].header;
4398 * Sets the header for a column.
4399 * @param {Number} col The column index
4400 * @param {String} header The new header
4402 setColumnHeader : function(col, header){
4403 this.config[col].header = header;
4404 this.fireEvent("headerchange", this, col, header);
4408 * Returns the tooltip for the specified column.
4409 * @param {Number} col The column index
4412 getColumnTooltip : function(col){
4413 return this.config[col].tooltip;
4416 * Sets the tooltip for a column.
4417 * @param {Number} col The column index
4418 * @param {String} tooltip The new tooltip
4420 setColumnTooltip : function(col, tooltip){
4421 this.config[col].tooltip = tooltip;
4425 * Returns the dataIndex for the specified column.
4426 * @param {Number} col The column index
4429 getDataIndex : function(col){
4430 return this.config[col].dataIndex;
4434 * Sets the dataIndex for a column.
4435 * @param {Number} col The column index
4436 * @param {Number} dataIndex The new dataIndex
4438 setDataIndex : function(col, dataIndex){
4439 this.config[col].dataIndex = dataIndex;
4445 * Returns true if the cell is editable.
4446 * @param {Number} colIndex The column index
4447 * @param {Number} rowIndex The row index
4450 isCellEditable : function(colIndex, rowIndex){
4451 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4455 * Returns the editor defined for the cell/column.
4456 * return false or null to disable editing.
4457 * @param {Number} colIndex The column index
4458 * @param {Number} rowIndex The row index
4461 getCellEditor : function(colIndex, rowIndex){
4462 return this.config[colIndex].editor;
4466 * Sets if a column is editable.
4467 * @param {Number} col The column index
4468 * @param {Boolean} editable True if the column is editable
4470 setEditable : function(col, editable){
4471 this.config[col].editable = editable;
4476 * Returns true if the column is hidden.
4477 * @param {Number} colIndex The column index
4480 isHidden : function(colIndex){
4481 return this.config[colIndex].hidden;
4486 * Returns true if the column width cannot be changed
4488 isFixed : function(colIndex){
4489 return this.config[colIndex].fixed;
4493 * Returns true if the column can be resized
4496 isResizable : function(colIndex){
4497 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4500 * Sets if a column is hidden.
4501 * @param {Number} colIndex The column index
4502 * @param {Boolean} hidden True if the column is hidden
4504 setHidden : function(colIndex, hidden){
4505 this.config[colIndex].hidden = hidden;
4506 this.totalWidth = null;
4507 this.fireEvent("hiddenchange", this, colIndex, hidden);
4511 * Sets the editor for a column.
4512 * @param {Number} col The column index
4513 * @param {Object} editor The editor object
4515 setEditor : function(col, editor){
4516 this.config[col].editor = editor;
4520 Roo.grid.ColumnModel.defaultRenderer = function(value){
4521 if(typeof value == "string" && value.length < 1){
4527 // Alias for backwards compatibility
4528 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4531 * Ext JS Library 1.1.1
4532 * Copyright(c) 2006-2007, Ext JS, LLC.
4534 * Originally Released Under LGPL - original licence link has changed is not relivant.
4537 * <script type="text/javascript">
4541 * @class Roo.LoadMask
4542 * A simple utility class for generically masking elements while loading data. If the element being masked has
4543 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4544 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4545 * element's UpdateManager load indicator and will be destroyed after the initial load.
4547 * Create a new LoadMask
4548 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4549 * @param {Object} config The config object
4551 Roo.LoadMask = function(el, config){
4552 this.el = Roo.get(el);
4553 Roo.apply(this, config);
4555 this.store.on('beforeload', this.onBeforeLoad, this);
4556 this.store.on('load', this.onLoad, this);
4557 this.store.on('loadexception', this.onLoadException, this);
4558 this.removeMask = false;
4560 var um = this.el.getUpdateManager();
4561 um.showLoadIndicator = false; // disable the default indicator
4562 um.on('beforeupdate', this.onBeforeLoad, this);
4563 um.on('update', this.onLoad, this);
4564 um.on('failure', this.onLoad, this);
4565 this.removeMask = true;
4569 Roo.LoadMask.prototype = {
4571 * @cfg {Boolean} removeMask
4572 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4573 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4577 * The text to display in a centered loading message box (defaults to 'Loading...')
4581 * @cfg {String} msgCls
4582 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4584 msgCls : 'x-mask-loading',
4587 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4593 * Disables the mask to prevent it from being displayed
4595 disable : function(){
4596 this.disabled = true;
4600 * Enables the mask so that it can be displayed
4602 enable : function(){
4603 this.disabled = false;
4606 onLoadException : function()
4610 if (typeof(arguments[3]) != 'undefined') {
4611 Roo.MessageBox.alert("Error loading",arguments[3]);
4615 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4616 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4625 this.el.unmask(this.removeMask);
4630 this.el.unmask(this.removeMask);
4634 onBeforeLoad : function(){
4636 this.el.mask(this.msg, this.msgCls);
4641 destroy : function(){
4643 this.store.un('beforeload', this.onBeforeLoad, this);
4644 this.store.un('load', this.onLoad, this);
4645 this.store.un('loadexception', this.onLoadException, this);
4647 var um = this.el.getUpdateManager();
4648 um.un('beforeupdate', this.onBeforeLoad, this);
4649 um.un('update', this.onLoad, this);
4650 um.un('failure', this.onLoad, this);
4661 * @class Roo.bootstrap.Table
4662 * @extends Roo.bootstrap.Component
4663 * Bootstrap Table class
4664 * @cfg {String} cls table class
4665 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4666 * @cfg {String} bgcolor Specifies the background color for a table
4667 * @cfg {Number} border Specifies whether the table cells should have borders or not
4668 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4669 * @cfg {Number} cellspacing Specifies the space between cells
4670 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4671 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4672 * @cfg {String} sortable Specifies that the table should be sortable
4673 * @cfg {String} summary Specifies a summary of the content of a table
4674 * @cfg {Number} width Specifies the width of a table
4675 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4677 * @cfg {boolean} striped Should the rows be alternative striped
4678 * @cfg {boolean} bordered Add borders to the table
4679 * @cfg {boolean} hover Add hover highlighting
4680 * @cfg {boolean} condensed Format condensed
4681 * @cfg {boolean} responsive Format condensed
4682 * @cfg {Boolean} loadMask (true|false) default false
4683 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4684 * @cfg {Boolean} thead (true|false) generate thead, default true
4685 * @cfg {Boolean} RowSelection (true|false) default false
4686 * @cfg {Boolean} CellSelection (true|false) default false
4688 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4692 * Create a new Table
4693 * @param {Object} config The config object
4696 Roo.bootstrap.Table = function(config){
4697 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4700 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4701 this.sm = this.selModel;
4702 this.sm.xmodule = this.xmodule || false;
4704 if (this.cm && typeof(this.cm.config) == 'undefined') {
4705 this.colModel = new Roo.grid.ColumnModel(this.cm);
4706 this.cm = this.colModel;
4707 this.cm.xmodule = this.xmodule || false;
4710 this.store= Roo.factory(this.store, Roo.data);
4711 this.ds = this.store;
4712 this.ds.xmodule = this.xmodule || false;
4715 if (this.footer && this.store) {
4716 this.footer.dataSource = this.ds;
4717 this.footer = Roo.factory(this.footer);
4724 * Fires when a cell is clicked
4725 * @param {Roo.bootstrap.Table} this
4726 * @param {Roo.Element} el
4727 * @param {Number} rowIndex
4728 * @param {Number} columnIndex
4729 * @param {Roo.EventObject} e
4733 * @event celldblclick
4734 * Fires when a cell is double clicked
4735 * @param {Roo.bootstrap.Table} this
4736 * @param {Roo.Element} el
4737 * @param {Number} rowIndex
4738 * @param {Number} columnIndex
4739 * @param {Roo.EventObject} e
4741 "celldblclick" : true,
4744 * Fires when a row is clicked
4745 * @param {Roo.bootstrap.Table} this
4746 * @param {Roo.Element} el
4747 * @param {Number} rowIndex
4748 * @param {Roo.EventObject} e
4752 * @event rowdblclick
4753 * Fires when a row is double clicked
4754 * @param {Roo.bootstrap.Table} this
4755 * @param {Roo.Element} el
4756 * @param {Number} rowIndex
4757 * @param {Roo.EventObject} e
4759 "rowdblclick" : true,
4762 * Fires when a mouseover occur
4763 * @param {Roo.bootstrap.Table} this
4764 * @param {Roo.Element} el
4765 * @param {Number} rowIndex
4766 * @param {Number} columnIndex
4767 * @param {Roo.EventObject} e
4772 * Fires when a mouseout occur
4773 * @param {Roo.bootstrap.Table} this
4774 * @param {Roo.Element} el
4775 * @param {Number} rowIndex
4776 * @param {Number} columnIndex
4777 * @param {Roo.EventObject} e
4782 * Fires when a row is rendered, so you can change add a style to it.
4783 * @param {Roo.bootstrap.Table} this
4784 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4791 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4815 RowSelection : false,
4816 CellSelection : false,
4819 // Roo.Element - the tbody
4822 getAutoCreate : function(){
4823 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4832 cfg.cls += ' table-striped';
4836 cfg.cls += ' table-hover';
4838 if (this.bordered) {
4839 cfg.cls += ' table-bordered';
4841 if (this.condensed) {
4842 cfg.cls += ' table-condensed';
4844 if (this.responsive) {
4845 cfg.cls += ' table-responsive';
4849 cfg.cls+= ' ' +this.cls;
4852 // this lot should be simplifed...
4855 cfg.align=this.align;
4858 cfg.bgcolor=this.bgcolor;
4861 cfg.border=this.border;
4863 if (this.cellpadding) {
4864 cfg.cellpadding=this.cellpadding;
4866 if (this.cellspacing) {
4867 cfg.cellspacing=this.cellspacing;
4870 cfg.frame=this.frame;
4873 cfg.rules=this.rules;
4875 if (this.sortable) {
4876 cfg.sortable=this.sortable;
4879 cfg.summary=this.summary;
4882 cfg.width=this.width;
4885 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4888 if(this.store || this.cm){
4890 cfg.cn.push(this.renderHeader());
4893 cfg.cn.push(this.renderBody());
4896 cfg.cn.push(this.renderFooter());
4899 cfg.cls+= ' TableGrid';
4902 return { cn : [ cfg ] };
4905 initEvents : function()
4907 if(!this.store || !this.cm){
4911 //Roo.log('initEvents with ds!!!!');
4913 this.mainBody = this.el.select('tbody', true).first();
4918 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4919 e.on('click', _this.sort, _this);
4922 this.el.on("click", this.onClick, this);
4923 this.el.on("dblclick", this.onDblClick, this);
4925 this.parent().el.setStyle('position', 'relative');
4927 this.footer.parentId = this.id;
4928 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4931 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4933 this.store.on('load', this.onLoad, this);
4934 this.store.on('beforeload', this.onBeforeLoad, this);
4935 this.store.on('update', this.onUpdate, this);
4939 onMouseover : function(e, el)
4941 var cell = Roo.get(el);
4947 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4948 cell = cell.findParent('td', false, true);
4951 var row = cell.findParent('tr', false, true);
4952 var cellIndex = cell.dom.cellIndex;
4953 var rowIndex = row.dom.rowIndex - 1; // start from 0
4955 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4959 onMouseout : function(e, el)
4961 var cell = Roo.get(el);
4967 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4968 cell = cell.findParent('td', false, true);
4971 var row = cell.findParent('tr', false, true);
4972 var cellIndex = cell.dom.cellIndex;
4973 var rowIndex = row.dom.rowIndex - 1; // start from 0
4975 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4979 onClick : function(e, el)
4981 var cell = Roo.get(el);
4983 if(!cell || (!this.CellSelection && !this.RowSelection)){
4988 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4989 cell = cell.findParent('td', false, true);
4992 var row = cell.findParent('tr', false, true);
4993 var cellIndex = cell.dom.cellIndex;
4994 var rowIndex = row.dom.rowIndex - 1;
4996 if(this.CellSelection){
4997 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5000 if(this.RowSelection){
5001 this.fireEvent('rowclick', this, row, rowIndex, e);
5007 onDblClick : function(e,el)
5009 var cell = Roo.get(el);
5011 if(!cell || (!this.CellSelection && !this.RowSelection)){
5015 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5016 cell = cell.findParent('td', false, true);
5019 var row = cell.findParent('tr', false, true);
5020 var cellIndex = cell.dom.cellIndex;
5021 var rowIndex = row.dom.rowIndex - 1;
5023 if(this.CellSelection){
5024 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5027 if(this.RowSelection){
5028 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5032 sort : function(e,el)
5034 var col = Roo.get(el)
5036 if(!col.hasClass('sortable')){
5040 var sort = col.attr('sort');
5043 if(col.hasClass('glyphicon-arrow-up')){
5047 this.store.sortInfo = {field : sort, direction : dir};
5050 Roo.log("calling footer first");
5051 this.footer.onClick('first');
5054 this.store.load({ params : { start : 0 } });
5058 renderHeader : function()
5067 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5069 var config = cm.config[i];
5074 html: cm.getColumnHeader(i)
5077 if(typeof(config.hidden) != 'undefined' && config.hidden){
5078 c.style += ' display:none;';
5081 if(typeof(config.dataIndex) != 'undefined'){
5082 c.sort = config.dataIndex;
5085 if(typeof(config.sortable) != 'undefined' && config.sortable){
5089 if(typeof(config.align) != 'undefined' && config.align.length){
5090 c.style += ' text-align:' + config.align + ';';
5093 if(typeof(config.width) != 'undefined'){
5094 c.style += ' width:' + config.width + 'px;';
5103 renderBody : function()
5113 colspan : this.cm.getColumnCount()
5123 renderFooter : function()
5133 colspan : this.cm.getColumnCount()
5147 Roo.log('ds onload');
5152 var ds = this.store;
5154 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5155 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5157 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5158 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5161 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5162 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5166 var tbody = this.mainBody;
5168 if(ds.getCount() > 0){
5169 ds.data.each(function(d,rowIndex){
5170 var row = this.renderRow(cm, ds, rowIndex);
5172 tbody.createChild(row);
5176 if(row.cellObjects.length){
5177 Roo.each(row.cellObjects, function(r){
5178 _this.renderCellObject(r);
5185 Roo.each(this.el.select('tbody td', true).elements, function(e){
5186 e.on('mouseover', _this.onMouseover, _this);
5189 Roo.each(this.el.select('tbody td', true).elements, function(e){
5190 e.on('mouseout', _this.onMouseout, _this);
5193 //if(this.loadMask){
5194 // this.maskEl.hide();
5199 onUpdate : function(ds,record)
5201 this.refreshRow(record);
5203 onRemove : function(ds, record, index, isUpdate){
5204 if(isUpdate !== true){
5205 this.fireEvent("beforerowremoved", this, index, record);
5207 var bt = this.mainBody.dom;
5209 bt.removeChild(bt.rows[index]);
5212 if(isUpdate !== true){
5213 //this.stripeRows(index);
5214 //this.syncRowHeights(index, index);
5216 this.fireEvent("rowremoved", this, index, record);
5221 refreshRow : function(record){
5222 var ds = this.store, index;
5223 if(typeof record == 'number'){
5225 record = ds.getAt(index);
5227 index = ds.indexOf(record);
5229 this.insertRow(ds, index, true);
5230 this.onRemove(ds, record, index+1, true);
5231 //this.syncRowHeights(index, index);
5233 this.fireEvent("rowupdated", this, index, record);
5236 insertRow : function(dm, rowIndex, isUpdate){
5239 this.fireEvent("beforerowsinserted", this, rowIndex);
5241 //var s = this.getScrollState();
5242 var row = this.renderRow(this.cm, this.store, rowIndex);
5243 // insert before rowIndex..
5244 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5248 if(row.cellObjects.length){
5249 Roo.each(row.cellObjects, function(r){
5250 _this.renderCellObject(r);
5255 this.fireEvent("rowsinserted", this, rowIndex);
5256 //this.syncRowHeights(firstRow, lastRow);
5257 //this.stripeRows(firstRow);
5264 getRowDom : function(rowIndex)
5266 // not sure if I need to check this.. but let's do it anyway..
5267 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5268 this.mainBody.dom.rows[rowIndex] : false
5270 // returns the object tree for a tr..
5273 renderRow : function(cm, ds, rowIndex) {
5275 var d = ds.getAt(rowIndex);
5282 var cellObjects = [];
5284 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5285 var config = cm.config[i];
5287 var renderer = cm.getRenderer(i);
5291 if(typeof(renderer) !== 'undefined'){
5292 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5294 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5295 // and are rendered into the cells after the row is rendered - using the id for the element.
5297 if(typeof(value) === 'object'){
5307 rowIndex : rowIndex,
5312 this.fireEvent('rowclass', this, rowcfg);
5316 cls : rowcfg.rowClass,
5318 html: (typeof(value) === 'object') ? '' : value
5325 if(typeof(config.hidden) != 'undefined' && config.hidden){
5326 td.style += ' display:none;';
5329 if(typeof(config.align) != 'undefined' && config.align.length){
5330 td.style += ' text-align:' + config.align + ';';
5333 if(typeof(config.width) != 'undefined'){
5334 td.style += ' width:' + config.width + 'px;';
5341 row.cellObjects = cellObjects;
5349 onBeforeLoad : function()
5351 //Roo.log('ds onBeforeLoad');
5355 //if(this.loadMask){
5356 // this.maskEl.show();
5362 this.el.select('tbody', true).first().dom.innerHTML = '';
5365 getSelectionModel : function(){
5367 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5369 return this.selModel;
5372 * Render the Roo.bootstrap object from renderder
5374 renderCellObject : function(r)
5378 var t = r.cfg.render(r.container);
5381 Roo.each(r.cfg.cn, function(c){
5383 container: t.getChildContainer(),
5386 _this.renderCellObject(child);
5403 * @class Roo.bootstrap.TableCell
5404 * @extends Roo.bootstrap.Component
5405 * Bootstrap TableCell class
5406 * @cfg {String} html cell contain text
5407 * @cfg {String} cls cell class
5408 * @cfg {String} tag cell tag (td|th) default td
5409 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5410 * @cfg {String} align Aligns the content in a cell
5411 * @cfg {String} axis Categorizes cells
5412 * @cfg {String} bgcolor Specifies the background color of a cell
5413 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5414 * @cfg {Number} colspan Specifies the number of columns a cell should span
5415 * @cfg {String} headers Specifies one or more header cells a cell is related to
5416 * @cfg {Number} height Sets the height of a cell
5417 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5418 * @cfg {Number} rowspan Sets the number of rows a cell should span
5419 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5420 * @cfg {String} valign Vertical aligns the content in a cell
5421 * @cfg {Number} width Specifies the width of a cell
5424 * Create a new TableCell
5425 * @param {Object} config The config object
5428 Roo.bootstrap.TableCell = function(config){
5429 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5432 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5452 getAutoCreate : function(){
5453 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5473 cfg.align=this.align
5479 cfg.bgcolor=this.bgcolor
5482 cfg.charoff=this.charoff
5485 cfg.colspan=this.colspan
5488 cfg.headers=this.headers
5491 cfg.height=this.height
5494 cfg.nowrap=this.nowrap
5497 cfg.rowspan=this.rowspan
5500 cfg.scope=this.scope
5503 cfg.valign=this.valign
5506 cfg.width=this.width
5525 * @class Roo.bootstrap.TableRow
5526 * @extends Roo.bootstrap.Component
5527 * Bootstrap TableRow class
5528 * @cfg {String} cls row class
5529 * @cfg {String} align Aligns the content in a table row
5530 * @cfg {String} bgcolor Specifies a background color for a table row
5531 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5532 * @cfg {String} valign Vertical aligns the content in a table row
5535 * Create a new TableRow
5536 * @param {Object} config The config object
5539 Roo.bootstrap.TableRow = function(config){
5540 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5543 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5551 getAutoCreate : function(){
5552 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5562 cfg.align = this.align;
5565 cfg.bgcolor = this.bgcolor;
5568 cfg.charoff = this.charoff;
5571 cfg.valign = this.valign;
5589 * @class Roo.bootstrap.TableBody
5590 * @extends Roo.bootstrap.Component
5591 * Bootstrap TableBody class
5592 * @cfg {String} cls element class
5593 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5594 * @cfg {String} align Aligns the content inside the element
5595 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5596 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5599 * Create a new TableBody
5600 * @param {Object} config The config object
5603 Roo.bootstrap.TableBody = function(config){
5604 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5607 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5615 getAutoCreate : function(){
5616 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5630 cfg.align = this.align;
5633 cfg.charoff = this.charoff;
5636 cfg.valign = this.valign;
5643 // initEvents : function()
5650 // this.store = Roo.factory(this.store, Roo.data);
5651 // this.store.on('load', this.onLoad, this);
5653 // this.store.load();
5657 // onLoad: function ()
5659 // this.fireEvent('load', this);
5669 * Ext JS Library 1.1.1
5670 * Copyright(c) 2006-2007, Ext JS, LLC.
5672 * Originally Released Under LGPL - original licence link has changed is not relivant.
5675 * <script type="text/javascript">
5678 // as we use this in bootstrap.
5679 Roo.namespace('Roo.form');
5681 * @class Roo.form.Action
5682 * Internal Class used to handle form actions
5684 * @param {Roo.form.BasicForm} el The form element or its id
5685 * @param {Object} config Configuration options
5690 // define the action interface
5691 Roo.form.Action = function(form, options){
5693 this.options = options || {};
5696 * Client Validation Failed
5699 Roo.form.Action.CLIENT_INVALID = 'client';
5701 * Server Validation Failed
5704 Roo.form.Action.SERVER_INVALID = 'server';
5706 * Connect to Server Failed
5709 Roo.form.Action.CONNECT_FAILURE = 'connect';
5711 * Reading Data from Server Failed
5714 Roo.form.Action.LOAD_FAILURE = 'load';
5716 Roo.form.Action.prototype = {
5718 failureType : undefined,
5719 response : undefined,
5723 run : function(options){
5728 success : function(response){
5733 handleResponse : function(response){
5737 // default connection failure
5738 failure : function(response){
5740 this.response = response;
5741 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5742 this.form.afterAction(this, false);
5745 processResponse : function(response){
5746 this.response = response;
5747 if(!response.responseText){
5750 this.result = this.handleResponse(response);
5754 // utility functions used internally
5755 getUrl : function(appendParams){
5756 var url = this.options.url || this.form.url || this.form.el.dom.action;
5758 var p = this.getParams();
5760 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5766 getMethod : function(){
5767 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5770 getParams : function(){
5771 var bp = this.form.baseParams;
5772 var p = this.options.params;
5774 if(typeof p == "object"){
5775 p = Roo.urlEncode(Roo.applyIf(p, bp));
5776 }else if(typeof p == 'string' && bp){
5777 p += '&' + Roo.urlEncode(bp);
5780 p = Roo.urlEncode(bp);
5785 createCallback : function(){
5787 success: this.success,
5788 failure: this.failure,
5790 timeout: (this.form.timeout*1000),
5791 upload: this.form.fileUpload ? this.success : undefined
5796 Roo.form.Action.Submit = function(form, options){
5797 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5800 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5803 haveProgress : false,
5804 uploadComplete : false,
5806 // uploadProgress indicator.
5807 uploadProgress : function()
5809 if (!this.form.progressUrl) {
5813 if (!this.haveProgress) {
5814 Roo.MessageBox.progress("Uploading", "Uploading");
5816 if (this.uploadComplete) {
5817 Roo.MessageBox.hide();
5821 this.haveProgress = true;
5823 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5825 var c = new Roo.data.Connection();
5827 url : this.form.progressUrl,
5832 success : function(req){
5833 //console.log(data);
5837 rdata = Roo.decode(req.responseText)
5839 Roo.log("Invalid data from server..");
5843 if (!rdata || !rdata.success) {
5845 Roo.MessageBox.alert(Roo.encode(rdata));
5848 var data = rdata.data;
5850 if (this.uploadComplete) {
5851 Roo.MessageBox.hide();
5856 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5857 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5860 this.uploadProgress.defer(2000,this);
5863 failure: function(data) {
5864 Roo.log('progress url failed ');
5875 // run get Values on the form, so it syncs any secondary forms.
5876 this.form.getValues();
5878 var o = this.options;
5879 var method = this.getMethod();
5880 var isPost = method == 'POST';
5881 if(o.clientValidation === false || this.form.isValid()){
5883 if (this.form.progressUrl) {
5884 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5885 (new Date() * 1) + '' + Math.random());
5890 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5891 form:this.form.el.dom,
5892 url:this.getUrl(!isPost),
5894 params:isPost ? this.getParams() : null,
5895 isUpload: this.form.fileUpload
5898 this.uploadProgress();
5900 }else if (o.clientValidation !== false){ // client validation failed
5901 this.failureType = Roo.form.Action.CLIENT_INVALID;
5902 this.form.afterAction(this, false);
5906 success : function(response)
5908 this.uploadComplete= true;
5909 if (this.haveProgress) {
5910 Roo.MessageBox.hide();
5914 var result = this.processResponse(response);
5915 if(result === true || result.success){
5916 this.form.afterAction(this, true);
5920 this.form.markInvalid(result.errors);
5921 this.failureType = Roo.form.Action.SERVER_INVALID;
5923 this.form.afterAction(this, false);
5925 failure : function(response)
5927 this.uploadComplete= true;
5928 if (this.haveProgress) {
5929 Roo.MessageBox.hide();
5932 this.response = response;
5933 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5934 this.form.afterAction(this, false);
5937 handleResponse : function(response){
5938 if(this.form.errorReader){
5939 var rs = this.form.errorReader.read(response);
5942 for(var i = 0, len = rs.records.length; i < len; i++) {
5943 var r = rs.records[i];
5947 if(errors.length < 1){
5951 success : rs.success,
5957 ret = Roo.decode(response.responseText);
5961 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5971 Roo.form.Action.Load = function(form, options){
5972 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5973 this.reader = this.form.reader;
5976 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5981 Roo.Ajax.request(Roo.apply(
5982 this.createCallback(), {
5983 method:this.getMethod(),
5984 url:this.getUrl(false),
5985 params:this.getParams()
5989 success : function(response){
5991 var result = this.processResponse(response);
5992 if(result === true || !result.success || !result.data){
5993 this.failureType = Roo.form.Action.LOAD_FAILURE;
5994 this.form.afterAction(this, false);
5997 this.form.clearInvalid();
5998 this.form.setValues(result.data);
5999 this.form.afterAction(this, true);
6002 handleResponse : function(response){
6003 if(this.form.reader){
6004 var rs = this.form.reader.read(response);
6005 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6007 success : rs.success,
6011 return Roo.decode(response.responseText);
6015 Roo.form.Action.ACTION_TYPES = {
6016 'load' : Roo.form.Action.Load,
6017 'submit' : Roo.form.Action.Submit
6026 * @class Roo.bootstrap.Form
6027 * @extends Roo.bootstrap.Component
6028 * Bootstrap Form class
6029 * @cfg {String} method GET | POST (default POST)
6030 * @cfg {String} labelAlign top | left (default top)
6031 * @cfg {String} align left | right - for navbars
6036 * @param {Object} config The config object
6040 Roo.bootstrap.Form = function(config){
6041 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6044 * @event clientvalidation
6045 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6046 * @param {Form} this
6047 * @param {Boolean} valid true if the form has passed client-side validation
6049 clientvalidation: true,
6051 * @event beforeaction
6052 * Fires before any action is performed. Return false to cancel the action.
6053 * @param {Form} this
6054 * @param {Action} action The action to be performed
6058 * @event actionfailed
6059 * Fires when an action fails.
6060 * @param {Form} this
6061 * @param {Action} action The action that failed
6063 actionfailed : true,
6065 * @event actioncomplete
6066 * Fires when an action is completed.
6067 * @param {Form} this
6068 * @param {Action} action The action that completed
6070 actioncomplete : true
6075 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6078 * @cfg {String} method
6079 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6084 * The URL to use for form actions if one isn't supplied in the action options.
6087 * @cfg {Boolean} fileUpload
6088 * Set to true if this form is a file upload.
6092 * @cfg {Object} baseParams
6093 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6097 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6101 * @cfg {Sting} align (left|right) for navbar forms
6106 activeAction : null,
6109 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6110 * element by passing it or its id or mask the form itself by passing in true.
6113 waitMsgTarget : false,
6118 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6119 * element by passing it or its id or mask the form itself by passing in true.
6123 getAutoCreate : function(){
6127 method : this.method || 'POST',
6128 id : this.id || Roo.id(),
6131 if (this.parent().xtype.match(/^Nav/)) {
6132 cfg.cls = 'navbar-form navbar-' + this.align;
6136 if (this.labelAlign == 'left' ) {
6137 cfg.cls += ' form-horizontal';
6143 initEvents : function()
6145 this.el.on('submit', this.onSubmit, this);
6146 // this was added as random key presses on the form where triggering form submit.
6147 this.el.on('keypress', function(e) {
6148 if (e.getCharCode() != 13) {
6151 // we might need to allow it for textareas.. and some other items.
6152 // check e.getTarget().
6154 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6158 Roo.log("keypress blocked");
6166 onSubmit : function(e){
6171 * Returns true if client-side validation on the form is successful.
6174 isValid : function(){
6175 var items = this.getItems();
6177 items.each(function(f){
6186 * Returns true if any fields in this form have changed since their original load.
6189 isDirty : function(){
6191 var items = this.getItems();
6192 items.each(function(f){
6202 * Performs a predefined action (submit or load) or custom actions you define on this form.
6203 * @param {String} actionName The name of the action type
6204 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6205 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6206 * accept other config options):
6208 Property Type Description
6209 ---------------- --------------- ----------------------------------------------------------------------------------
6210 url String The url for the action (defaults to the form's url)
6211 method String The form method to use (defaults to the form's method, or POST if not defined)
6212 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6213 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6214 validate the form on the client (defaults to false)
6216 * @return {BasicForm} this
6218 doAction : function(action, options){
6219 if(typeof action == 'string'){
6220 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6222 if(this.fireEvent('beforeaction', this, action) !== false){
6223 this.beforeAction(action);
6224 action.run.defer(100, action);
6230 beforeAction : function(action){
6231 var o = action.options;
6233 // not really supported yet.. ??
6235 //if(this.waitMsgTarget === true){
6236 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6237 //}else if(this.waitMsgTarget){
6238 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6239 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6241 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6247 afterAction : function(action, success){
6248 this.activeAction = null;
6249 var o = action.options;
6251 //if(this.waitMsgTarget === true){
6253 //}else if(this.waitMsgTarget){
6254 // this.waitMsgTarget.unmask();
6256 // Roo.MessageBox.updateProgress(1);
6257 // Roo.MessageBox.hide();
6264 Roo.callback(o.success, o.scope, [this, action]);
6265 this.fireEvent('actioncomplete', this, action);
6269 // failure condition..
6270 // we have a scenario where updates need confirming.
6271 // eg. if a locking scenario exists..
6272 // we look for { errors : { needs_confirm : true }} in the response.
6274 (typeof(action.result) != 'undefined') &&
6275 (typeof(action.result.errors) != 'undefined') &&
6276 (typeof(action.result.errors.needs_confirm) != 'undefined')
6279 Roo.log("not supported yet");
6282 Roo.MessageBox.confirm(
6283 "Change requires confirmation",
6284 action.result.errorMsg,
6289 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6299 Roo.callback(o.failure, o.scope, [this, action]);
6300 // show an error message if no failed handler is set..
6301 if (!this.hasListener('actionfailed')) {
6302 Roo.log("need to add dialog support");
6304 Roo.MessageBox.alert("Error",
6305 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6306 action.result.errorMsg :
6307 "Saving Failed, please check your entries or try again"
6312 this.fireEvent('actionfailed', this, action);
6317 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6318 * @param {String} id The value to search for
6321 findField : function(id){
6322 var items = this.getItems();
6323 var field = items.get(id);
6325 items.each(function(f){
6326 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6333 return field || null;
6336 * Mark fields in this form invalid in bulk.
6337 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6338 * @return {BasicForm} this
6340 markInvalid : function(errors){
6341 if(errors instanceof Array){
6342 for(var i = 0, len = errors.length; i < len; i++){
6343 var fieldError = errors[i];
6344 var f = this.findField(fieldError.id);
6346 f.markInvalid(fieldError.msg);
6352 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6353 field.markInvalid(errors[id]);
6357 //Roo.each(this.childForms || [], function (f) {
6358 // f.markInvalid(errors);
6365 * Set values for fields in this form in bulk.
6366 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6367 * @return {BasicForm} this
6369 setValues : function(values){
6370 if(values instanceof Array){ // array of objects
6371 for(var i = 0, len = values.length; i < len; i++){
6373 var f = this.findField(v.id);
6375 f.setValue(v.value);
6376 if(this.trackResetOnLoad){
6377 f.originalValue = f.getValue();
6381 }else{ // object hash
6384 if(typeof values[id] != 'function' && (field = this.findField(id))){
6386 if (field.setFromData &&
6388 field.displayField &&
6389 // combos' with local stores can
6390 // be queried via setValue()
6391 // to set their value..
6392 (field.store && !field.store.isLocal)
6396 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6397 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6398 field.setFromData(sd);
6401 field.setValue(values[id]);
6405 if(this.trackResetOnLoad){
6406 field.originalValue = field.getValue();
6412 //Roo.each(this.childForms || [], function (f) {
6413 // f.setValues(values);
6420 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6421 * they are returned as an array.
6422 * @param {Boolean} asString
6425 getValues : function(asString){
6426 //if (this.childForms) {
6427 // copy values from the child forms
6428 // Roo.each(this.childForms, function (f) {
6429 // this.setValues(f.getValues());
6435 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6436 if(asString === true){
6439 return Roo.urlDecode(fs);
6443 * Returns the fields in this form as an object with key/value pairs.
6444 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6447 getFieldValues : function(with_hidden)
6449 var items = this.getItems();
6451 items.each(function(f){
6455 var v = f.getValue();
6456 if (f.inputType =='radio') {
6457 if (typeof(ret[f.getName()]) == 'undefined') {
6458 ret[f.getName()] = ''; // empty..
6461 if (!f.el.dom.checked) {
6469 // not sure if this supported any more..
6470 if ((typeof(v) == 'object') && f.getRawValue) {
6471 v = f.getRawValue() ; // dates..
6473 // combo boxes where name != hiddenName...
6474 if (f.name != f.getName()) {
6475 ret[f.name] = f.getRawValue();
6477 ret[f.getName()] = v;
6484 * Clears all invalid messages in this form.
6485 * @return {BasicForm} this
6487 clearInvalid : function(){
6488 var items = this.getItems();
6490 items.each(function(f){
6501 * @return {BasicForm} this
6504 var items = this.getItems();
6505 items.each(function(f){
6509 Roo.each(this.childForms || [], function (f) {
6516 getItems : function()
6518 var r=new Roo.util.MixedCollection(false, function(o){
6519 return o.id || (o.id = Roo.id());
6521 var iter = function(el) {
6528 Roo.each(el.items,function(e) {
6547 * Ext JS Library 1.1.1
6548 * Copyright(c) 2006-2007, Ext JS, LLC.
6550 * Originally Released Under LGPL - original licence link has changed is not relivant.
6553 * <script type="text/javascript">
6556 * @class Roo.form.VTypes
6557 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6560 Roo.form.VTypes = function(){
6561 // closure these in so they are only created once.
6562 var alpha = /^[a-zA-Z_]+$/;
6563 var alphanum = /^[a-zA-Z0-9_]+$/;
6564 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6565 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6567 // All these messages and functions are configurable
6570 * The function used to validate email addresses
6571 * @param {String} value The email address
6573 'email' : function(v){
6574 return email.test(v);
6577 * The error text to display when the email validation function returns false
6580 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6582 * The keystroke filter mask to be applied on email input
6585 'emailMask' : /[a-z0-9_\.\-@]/i,
6588 * The function used to validate URLs
6589 * @param {String} value The URL
6591 'url' : function(v){
6595 * The error text to display when the url validation function returns false
6598 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6601 * The function used to validate alpha values
6602 * @param {String} value The value
6604 'alpha' : function(v){
6605 return alpha.test(v);
6608 * The error text to display when the alpha validation function returns false
6611 'alphaText' : 'This field should only contain letters and _',
6613 * The keystroke filter mask to be applied on alpha input
6616 'alphaMask' : /[a-z_]/i,
6619 * The function used to validate alphanumeric values
6620 * @param {String} value The value
6622 'alphanum' : function(v){
6623 return alphanum.test(v);
6626 * The error text to display when the alphanumeric validation function returns false
6629 'alphanumText' : 'This field should only contain letters, numbers and _',
6631 * The keystroke filter mask to be applied on alphanumeric input
6634 'alphanumMask' : /[a-z0-9_]/i
6644 * @class Roo.bootstrap.Input
6645 * @extends Roo.bootstrap.Component
6646 * Bootstrap Input class
6647 * @cfg {Boolean} disabled is it disabled
6648 * @cfg {String} fieldLabel - the label associated
6649 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6650 * @cfg {String} name name of the input
6651 * @cfg {string} fieldLabel - the label associated
6652 * @cfg {string} inputType - input / file submit ...
6653 * @cfg {string} placeholder - placeholder to put in text.
6654 * @cfg {string} before - input group add on before
6655 * @cfg {string} after - input group add on after
6656 * @cfg {string} size - (lg|sm) or leave empty..
6657 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6658 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6659 * @cfg {Number} md colspan out of 12 for computer-sized screens
6660 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6661 * @cfg {string} value default value of the input
6662 * @cfg {Number} labelWidth set the width of label (0-12)
6663 * @cfg {String} labelAlign (top|left)
6664 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6665 * @cfg {String} align (left|center|right) Default left
6669 * Create a new Input
6670 * @param {Object} config The config object
6673 Roo.bootstrap.Input = function(config){
6674 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6679 * Fires when this field receives input focus.
6680 * @param {Roo.form.Field} this
6685 * Fires when this field loses input focus.
6686 * @param {Roo.form.Field} this
6691 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6692 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6693 * @param {Roo.form.Field} this
6694 * @param {Roo.EventObject} e The event object
6699 * Fires just before the field blurs if the field value has changed.
6700 * @param {Roo.form.Field} this
6701 * @param {Mixed} newValue The new value
6702 * @param {Mixed} oldValue The original value
6707 * Fires after the field has been marked as invalid.
6708 * @param {Roo.form.Field} this
6709 * @param {String} msg The validation message
6714 * Fires after the field has been validated with no errors.
6715 * @param {Roo.form.Field} this
6720 * Fires after the key up
6721 * @param {Roo.form.Field} this
6722 * @param {Roo.EventObject} e The event Object
6728 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6730 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6731 automatic validation (defaults to "keyup").
6733 validationEvent : "keyup",
6735 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6737 validateOnBlur : true,
6739 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6741 validationDelay : 250,
6743 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6745 focusClass : "x-form-focus", // not needed???
6749 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6751 invalidClass : "has-error",
6754 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6756 selectOnFocus : false,
6759 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6763 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6768 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6770 disableKeyFilter : false,
6773 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6777 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6781 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6783 blankText : "This field is required",
6786 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6790 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6792 maxLength : Number.MAX_VALUE,
6794 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6796 minLengthText : "The minimum length for this field is {0}",
6798 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6800 maxLengthText : "The maximum length for this field is {0}",
6804 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6805 * If available, this function will be called only after the basic validators all return true, and will be passed the
6806 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6810 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6811 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6812 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6816 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6839 formatedValue : false,
6841 parentLabelAlign : function()
6844 while (parent.parent()) {
6845 parent = parent.parent();
6846 if (typeof(parent.labelAlign) !='undefined') {
6847 return parent.labelAlign;
6854 getAutoCreate : function(){
6856 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6862 if(this.inputType != 'hidden'){
6863 cfg.cls = 'form-group' //input-group
6869 type : this.inputType,
6871 cls : 'form-control',
6872 placeholder : this.placeholder || ''
6877 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6880 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6881 input.maxLength = this.maxLength;
6884 if (this.disabled) {
6885 input.disabled=true;
6888 if (this.readOnly) {
6889 input.readonly=true;
6893 input.name = this.name;
6896 input.cls += ' input-' + this.size;
6899 ['xs','sm','md','lg'].map(function(size){
6900 if (settings[size]) {
6901 cfg.cls += ' col-' + size + '-' + settings[size];
6905 var inputblock = input;
6907 if (this.before || this.after) {
6910 cls : 'input-group',
6913 if (this.before && typeof(this.before) == 'string') {
6915 inputblock.cn.push({
6917 cls : 'roo-input-before input-group-addon',
6921 if (this.before && typeof(this.before) == 'object') {
6922 this.before = Roo.factory(this.before);
6923 Roo.log(this.before);
6924 inputblock.cn.push({
6926 cls : 'roo-input-before input-group-' +
6927 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6931 inputblock.cn.push(input);
6933 if (this.after && typeof(this.after) == 'string') {
6934 inputblock.cn.push({
6936 cls : 'roo-input-after input-group-addon',
6940 if (this.after && typeof(this.after) == 'object') {
6941 this.after = Roo.factory(this.after);
6942 Roo.log(this.after);
6943 inputblock.cn.push({
6945 cls : 'roo-input-after input-group-' +
6946 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6951 if (align ==='left' && this.fieldLabel.length) {
6952 Roo.log("left and has label");
6958 cls : 'control-label col-sm-' + this.labelWidth,
6959 html : this.fieldLabel
6963 cls : "col-sm-" + (12 - this.labelWidth),
6970 } else if ( this.fieldLabel.length) {
6976 //cls : 'input-group-addon',
6977 html : this.fieldLabel
6987 Roo.log(" no label && no align");
6996 Roo.log('input-parentType: ' + this.parentType);
6998 if (this.parentType === 'Navbar' && this.parent().bar) {
6999 cfg.cls += ' navbar-form';
7007 * return the real input element.
7009 inputEl: function ()
7011 return this.el.select('input.form-control',true).first();
7013 setDisabled : function(v)
7015 var i = this.inputEl().dom;
7017 i.removeAttribute('disabled');
7021 i.setAttribute('disabled','true');
7023 initEvents : function()
7026 this.inputEl().on("keydown" , this.fireKey, this);
7027 this.inputEl().on("focus", this.onFocus, this);
7028 this.inputEl().on("blur", this.onBlur, this);
7030 this.inputEl().relayEvent('keyup', this);
7032 // reference to original value for reset
7033 this.originalValue = this.getValue();
7034 //Roo.form.TextField.superclass.initEvents.call(this);
7035 if(this.validationEvent == 'keyup'){
7036 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7037 this.inputEl().on('keyup', this.filterValidation, this);
7039 else if(this.validationEvent !== false){
7040 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7043 if(this.selectOnFocus){
7044 this.on("focus", this.preFocus, this);
7047 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7048 this.inputEl().on("keypress", this.filterKeys, this);
7051 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7052 this.el.on("click", this.autoSize, this);
7055 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7056 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7059 if (typeof(this.before) == 'object') {
7060 this.before.render(this.el.select('.roo-input-before',true).first());
7062 if (typeof(this.after) == 'object') {
7063 this.after.render(this.el.select('.roo-input-after',true).first());
7068 filterValidation : function(e){
7069 if(!e.isNavKeyPress()){
7070 this.validationTask.delay(this.validationDelay);
7074 * Validates the field value
7075 * @return {Boolean} True if the value is valid, else false
7077 validate : function(){
7078 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7079 if(this.disabled || this.validateValue(this.getRawValue())){
7080 this.clearInvalid();
7088 * Validates a value according to the field's validation rules and marks the field as invalid
7089 * if the validation fails
7090 * @param {Mixed} value The value to validate
7091 * @return {Boolean} True if the value is valid, else false
7093 validateValue : function(value){
7094 if(value.length < 1) { // if it's blank
7095 if(this.allowBlank){
7096 this.clearInvalid();
7099 this.markInvalid(this.blankText);
7103 if(value.length < this.minLength){
7104 this.markInvalid(String.format(this.minLengthText, this.minLength));
7107 if(value.length > this.maxLength){
7108 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7112 var vt = Roo.form.VTypes;
7113 if(!vt[this.vtype](value, this)){
7114 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7118 if(typeof this.validator == "function"){
7119 var msg = this.validator(value);
7121 this.markInvalid(msg);
7125 if(this.regex && !this.regex.test(value)){
7126 this.markInvalid(this.regexText);
7135 fireKey : function(e){
7136 //Roo.log('field ' + e.getKey());
7137 if(e.isNavKeyPress()){
7138 this.fireEvent("specialkey", this, e);
7141 focus : function (selectText){
7143 this.inputEl().focus();
7144 if(selectText === true){
7145 this.inputEl().dom.select();
7151 onFocus : function(){
7152 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7153 // this.el.addClass(this.focusClass);
7156 this.hasFocus = true;
7157 this.startValue = this.getValue();
7158 this.fireEvent("focus", this);
7162 beforeBlur : Roo.emptyFn,
7166 onBlur : function(){
7168 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7169 //this.el.removeClass(this.focusClass);
7171 this.hasFocus = false;
7172 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7175 var v = this.getValue();
7176 if(String(v) !== String(this.startValue)){
7177 this.fireEvent('change', this, v, this.startValue);
7179 this.fireEvent("blur", this);
7183 * Resets the current field value to the originally loaded value and clears any validation messages
7186 this.setValue(this.originalValue);
7187 this.clearInvalid();
7190 * Returns the name of the field
7191 * @return {Mixed} name The name field
7193 getName: function(){
7197 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7198 * @return {Mixed} value The field value
7200 getValue : function(){
7202 var v = this.inputEl().getValue();
7207 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7208 * @return {Mixed} value The field value
7210 getRawValue : function(){
7211 var v = this.inputEl().getValue();
7217 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7218 * @param {Mixed} value The value to set
7220 setRawValue : function(v){
7221 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7224 selectText : function(start, end){
7225 var v = this.getRawValue();
7227 start = start === undefined ? 0 : start;
7228 end = end === undefined ? v.length : end;
7229 var d = this.inputEl().dom;
7230 if(d.setSelectionRange){
7231 d.setSelectionRange(start, end);
7232 }else if(d.createTextRange){
7233 var range = d.createTextRange();
7234 range.moveStart("character", start);
7235 range.moveEnd("character", v.length-end);
7242 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7243 * @param {Mixed} value The value to set
7245 setValue : function(v){
7248 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7254 processValue : function(value){
7255 if(this.stripCharsRe){
7256 var newValue = value.replace(this.stripCharsRe, '');
7257 if(newValue !== value){
7258 this.setRawValue(newValue);
7265 preFocus : function(){
7267 if(this.selectOnFocus){
7268 this.inputEl().dom.select();
7271 filterKeys : function(e){
7273 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7276 var c = e.getCharCode(), cc = String.fromCharCode(c);
7277 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7280 if(!this.maskRe.test(cc)){
7285 * Clear any invalid styles/messages for this field
7287 clearInvalid : function(){
7289 if(!this.el || this.preventMark){ // not rendered
7292 this.el.removeClass(this.invalidClass);
7294 switch(this.msgTarget){
7296 this.el.dom.qtip = '';
7299 this.el.dom.title = '';
7303 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7308 this.errorIcon.dom.qtip = '';
7309 this.errorIcon.hide();
7310 this.un('resize', this.alignErrorIcon, this);
7314 var t = Roo.getDom(this.msgTarget);
7316 t.style.display = 'none';
7320 this.fireEvent('valid', this);
7323 * Mark this field as invalid
7324 * @param {String} msg The validation message
7326 markInvalid : function(msg){
7327 if(!this.el || this.preventMark){ // not rendered
7330 this.el.addClass(this.invalidClass);
7332 msg = msg || this.invalidText;
7333 switch(this.msgTarget){
7335 this.el.dom.qtip = msg;
7336 this.el.dom.qclass = 'x-form-invalid-tip';
7337 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7338 Roo.QuickTips.enable();
7342 this.el.dom.title = msg;
7346 var elp = this.el.findParent('.x-form-element', 5, true);
7347 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7348 this.errorEl.setWidth(elp.getWidth(true)-20);
7350 this.errorEl.update(msg);
7351 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7354 if(!this.errorIcon){
7355 var elp = this.el.findParent('.x-form-element', 5, true);
7356 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7358 this.alignErrorIcon();
7359 this.errorIcon.dom.qtip = msg;
7360 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7361 this.errorIcon.show();
7362 this.on('resize', this.alignErrorIcon, this);
7365 var t = Roo.getDom(this.msgTarget);
7367 t.style.display = this.msgDisplay;
7371 this.fireEvent('invalid', this, msg);
7374 SafariOnKeyDown : function(event)
7376 // this is a workaround for a password hang bug on chrome/ webkit.
7378 var isSelectAll = false;
7380 if(this.inputEl().dom.selectionEnd > 0){
7381 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7383 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7384 event.preventDefault();
7389 if(isSelectAll){ // backspace and delete key
7391 event.preventDefault();
7392 // this is very hacky as keydown always get's upper case.
7394 var cc = String.fromCharCode(event.getCharCode());
7395 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7399 adjustWidth : function(tag, w){
7400 tag = tag.toLowerCase();
7401 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7402 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7406 if(tag == 'textarea'){
7409 }else if(Roo.isOpera){
7413 if(tag == 'textarea'){
7432 * @class Roo.bootstrap.TextArea
7433 * @extends Roo.bootstrap.Input
7434 * Bootstrap TextArea class
7435 * @cfg {Number} cols Specifies the visible width of a text area
7436 * @cfg {Number} rows Specifies the visible number of lines in a text area
7437 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7438 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7439 * @cfg {string} html text
7442 * Create a new TextArea
7443 * @param {Object} config The config object
7446 Roo.bootstrap.TextArea = function(config){
7447 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7451 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7461 getAutoCreate : function(){
7463 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7474 value : this.value || '',
7475 html: this.html || '',
7476 cls : 'form-control',
7477 placeholder : this.placeholder || ''
7481 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7482 input.maxLength = this.maxLength;
7486 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7490 input.cols = this.cols;
7493 if (this.readOnly) {
7494 input.readonly = true;
7498 input.name = this.name;
7502 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7506 ['xs','sm','md','lg'].map(function(size){
7507 if (settings[size]) {
7508 cfg.cls += ' col-' + size + '-' + settings[size];
7512 var inputblock = input;
7514 if (this.before || this.after) {
7517 cls : 'input-group',
7521 inputblock.cn.push({
7523 cls : 'input-group-addon',
7527 inputblock.cn.push(input);
7529 inputblock.cn.push({
7531 cls : 'input-group-addon',
7538 if (align ==='left' && this.fieldLabel.length) {
7539 Roo.log("left and has label");
7545 cls : 'control-label col-sm-' + this.labelWidth,
7546 html : this.fieldLabel
7550 cls : "col-sm-" + (12 - this.labelWidth),
7557 } else if ( this.fieldLabel.length) {
7563 //cls : 'input-group-addon',
7564 html : this.fieldLabel
7574 Roo.log(" no label && no align");
7584 if (this.disabled) {
7585 input.disabled=true;
7592 * return the real textarea element.
7594 inputEl: function ()
7596 return this.el.select('textarea.form-control',true).first();
7604 * trigger field - base class for combo..
7609 * @class Roo.bootstrap.TriggerField
7610 * @extends Roo.bootstrap.Input
7611 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7612 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7613 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7614 * for which you can provide a custom implementation. For example:
7616 var trigger = new Roo.bootstrap.TriggerField();
7617 trigger.onTriggerClick = myTriggerFn;
7618 trigger.applyTo('my-field');
7621 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7622 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7623 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7624 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7626 * Create a new TriggerField.
7627 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7628 * to the base TextField)
7630 Roo.bootstrap.TriggerField = function(config){
7631 this.mimicing = false;
7632 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7635 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7637 * @cfg {String} triggerClass A CSS class to apply to the trigger
7640 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7644 /** @cfg {Boolean} grow @hide */
7645 /** @cfg {Number} growMin @hide */
7646 /** @cfg {Number} growMax @hide */
7652 autoSize: Roo.emptyFn,
7659 actionMode : 'wrap',
7663 getAutoCreate : function(){
7665 var align = this.labelAlign || this.parentLabelAlign();
7670 cls: 'form-group' //input-group
7677 type : this.inputType,
7678 cls : 'form-control',
7679 autocomplete: 'off',
7680 placeholder : this.placeholder || ''
7684 input.name = this.name;
7687 input.cls += ' input-' + this.size;
7690 if (this.disabled) {
7691 input.disabled=true;
7694 var inputblock = input;
7696 if (this.before || this.after) {
7699 cls : 'input-group',
7703 inputblock.cn.push({
7705 cls : 'input-group-addon',
7709 inputblock.cn.push(input);
7711 inputblock.cn.push({
7713 cls : 'input-group-addon',
7726 cls: 'form-hidden-field'
7734 Roo.log('multiple');
7742 cls: 'form-hidden-field'
7746 cls: 'select2-choices',
7750 cls: 'select2-search-field',
7763 cls: 'select2-container input-group',
7768 // cls: 'typeahead typeahead-long dropdown-menu',
7769 // style: 'display:none'
7777 cls : 'input-group-addon btn dropdown-toggle',
7785 cls: 'combobox-clear',
7799 combobox.cls += ' select2-container-multi';
7802 if (align ==='left' && this.fieldLabel.length) {
7804 Roo.log("left and has label");
7810 cls : 'control-label col-sm-' + this.labelWidth,
7811 html : this.fieldLabel
7815 cls : "col-sm-" + (12 - this.labelWidth),
7822 } else if ( this.fieldLabel.length) {
7828 //cls : 'input-group-addon',
7829 html : this.fieldLabel
7839 Roo.log(" no label && no align");
7846 ['xs','sm','md','lg'].map(function(size){
7847 if (settings[size]) {
7848 cfg.cls += ' col-' + size + '-' + settings[size];
7859 onResize : function(w, h){
7860 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7861 // if(typeof w == 'number'){
7862 // var x = w - this.trigger.getWidth();
7863 // this.inputEl().setWidth(this.adjustWidth('input', x));
7864 // this.trigger.setStyle('left', x+'px');
7869 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7872 getResizeEl : function(){
7873 return this.inputEl();
7877 getPositionEl : function(){
7878 return this.inputEl();
7882 alignErrorIcon : function(){
7883 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7887 initEvents : function(){
7891 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7892 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7894 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7895 if(this.hideTrigger){
7896 this.trigger.setDisplayed(false);
7898 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7902 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7905 //this.trigger.addClassOnOver('x-form-trigger-over');
7906 //this.trigger.addClassOnClick('x-form-trigger-click');
7909 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7913 createList : function()
7915 this.list = Roo.get(document.body).createChild({
7917 cls: 'typeahead typeahead-long dropdown-menu',
7918 style: 'display:none'
7921 this.list.setVisibilityMode(Roo.Element.DISPLAY);
7925 initTrigger : function(){
7930 onDestroy : function(){
7932 this.trigger.removeAllListeners();
7933 // this.trigger.remove();
7936 // this.wrap.remove();
7938 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7942 onFocus : function(){
7943 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7946 this.wrap.addClass('x-trigger-wrap-focus');
7947 this.mimicing = true;
7948 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7949 if(this.monitorTab){
7950 this.el.on("keydown", this.checkTab, this);
7957 checkTab : function(e){
7958 if(e.getKey() == e.TAB){
7964 onBlur : function(){
7969 mimicBlur : function(e, t){
7971 if(!this.wrap.contains(t) && this.validateBlur()){
7978 triggerBlur : function(){
7979 this.mimicing = false;
7980 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7981 if(this.monitorTab){
7982 this.el.un("keydown", this.checkTab, this);
7984 //this.wrap.removeClass('x-trigger-wrap-focus');
7985 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7989 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7990 validateBlur : function(e, t){
7995 onDisable : function(){
7996 this.inputEl().dom.disabled = true;
7997 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7999 // this.wrap.addClass('x-item-disabled');
8004 onEnable : function(){
8005 this.inputEl().dom.disabled = false;
8006 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8008 // this.el.removeClass('x-item-disabled');
8013 onShow : function(){
8014 var ae = this.getActionEl();
8017 ae.dom.style.display = '';
8018 ae.dom.style.visibility = 'visible';
8024 onHide : function(){
8025 var ae = this.getActionEl();
8026 ae.dom.style.display = 'none';
8030 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8031 * by an implementing function.
8033 * @param {EventObject} e
8035 onTriggerClick : Roo.emptyFn
8039 * Ext JS Library 1.1.1
8040 * Copyright(c) 2006-2007, Ext JS, LLC.
8042 * Originally Released Under LGPL - original licence link has changed is not relivant.
8045 * <script type="text/javascript">
8050 * @class Roo.data.SortTypes
8052 * Defines the default sorting (casting?) comparison functions used when sorting data.
8054 Roo.data.SortTypes = {
8056 * Default sort that does nothing
8057 * @param {Mixed} s The value being converted
8058 * @return {Mixed} The comparison value
8065 * The regular expression used to strip tags
8069 stripTagsRE : /<\/?[^>]+>/gi,
8072 * Strips all HTML tags to sort on text only
8073 * @param {Mixed} s The value being converted
8074 * @return {String} The comparison value
8076 asText : function(s){
8077 return String(s).replace(this.stripTagsRE, "");
8081 * Strips all HTML tags to sort on text only - Case insensitive
8082 * @param {Mixed} s The value being converted
8083 * @return {String} The comparison value
8085 asUCText : function(s){
8086 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8090 * Case insensitive string
8091 * @param {Mixed} s The value being converted
8092 * @return {String} The comparison value
8094 asUCString : function(s) {
8095 return String(s).toUpperCase();
8100 * @param {Mixed} s The value being converted
8101 * @return {Number} The comparison value
8103 asDate : function(s) {
8107 if(s instanceof Date){
8110 return Date.parse(String(s));
8115 * @param {Mixed} s The value being converted
8116 * @return {Float} The comparison value
8118 asFloat : function(s) {
8119 var val = parseFloat(String(s).replace(/,/g, ""));
8120 if(isNaN(val)) val = 0;
8126 * @param {Mixed} s The value being converted
8127 * @return {Number} The comparison value
8129 asInt : function(s) {
8130 var val = parseInt(String(s).replace(/,/g, ""));
8131 if(isNaN(val)) val = 0;
8136 * Ext JS Library 1.1.1
8137 * Copyright(c) 2006-2007, Ext JS, LLC.
8139 * Originally Released Under LGPL - original licence link has changed is not relivant.
8142 * <script type="text/javascript">
8146 * @class Roo.data.Record
8147 * Instances of this class encapsulate both record <em>definition</em> information, and record
8148 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8149 * to access Records cached in an {@link Roo.data.Store} object.<br>
8151 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8152 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8155 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8157 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8158 * {@link #create}. The parameters are the same.
8159 * @param {Array} data An associative Array of data values keyed by the field name.
8160 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8161 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8162 * not specified an integer id is generated.
8164 Roo.data.Record = function(data, id){
8165 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8170 * Generate a constructor for a specific record layout.
8171 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8172 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8173 * Each field definition object may contain the following properties: <ul>
8174 * <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,
8175 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8176 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8177 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8178 * is being used, then this is a string containing the javascript expression to reference the data relative to
8179 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8180 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8181 * this may be omitted.</p></li>
8182 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8183 * <ul><li>auto (Default, implies no conversion)</li>
8188 * <li>date</li></ul></p></li>
8189 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8190 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8191 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8192 * by the Reader into an object that will be stored in the Record. It is passed the
8193 * following parameters:<ul>
8194 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8196 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8198 * <br>usage:<br><pre><code>
8199 var TopicRecord = Roo.data.Record.create(
8200 {name: 'title', mapping: 'topic_title'},
8201 {name: 'author', mapping: 'username'},
8202 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8203 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8204 {name: 'lastPoster', mapping: 'user2'},
8205 {name: 'excerpt', mapping: 'post_text'}
8208 var myNewRecord = new TopicRecord({
8209 title: 'Do my job please',
8212 lastPost: new Date(),
8213 lastPoster: 'Animal',
8214 excerpt: 'No way dude!'
8216 myStore.add(myNewRecord);
8221 Roo.data.Record.create = function(o){
8223 f.superclass.constructor.apply(this, arguments);
8225 Roo.extend(f, Roo.data.Record);
8226 var p = f.prototype;
8227 p.fields = new Roo.util.MixedCollection(false, function(field){
8230 for(var i = 0, len = o.length; i < len; i++){
8231 p.fields.add(new Roo.data.Field(o[i]));
8233 f.getField = function(name){
8234 return p.fields.get(name);
8239 Roo.data.Record.AUTO_ID = 1000;
8240 Roo.data.Record.EDIT = 'edit';
8241 Roo.data.Record.REJECT = 'reject';
8242 Roo.data.Record.COMMIT = 'commit';
8244 Roo.data.Record.prototype = {
8246 * Readonly flag - true if this record has been modified.
8255 join : function(store){
8260 * Set the named field to the specified value.
8261 * @param {String} name The name of the field to set.
8262 * @param {Object} value The value to set the field to.
8264 set : function(name, value){
8265 if(this.data[name] == value){
8272 if(typeof this.modified[name] == 'undefined'){
8273 this.modified[name] = this.data[name];
8275 this.data[name] = value;
8276 if(!this.editing && this.store){
8277 this.store.afterEdit(this);
8282 * Get the value of the named field.
8283 * @param {String} name The name of the field to get the value of.
8284 * @return {Object} The value of the field.
8286 get : function(name){
8287 return this.data[name];
8291 beginEdit : function(){
8292 this.editing = true;
8297 cancelEdit : function(){
8298 this.editing = false;
8299 delete this.modified;
8303 endEdit : function(){
8304 this.editing = false;
8305 if(this.dirty && this.store){
8306 this.store.afterEdit(this);
8311 * Usually called by the {@link Roo.data.Store} which owns the Record.
8312 * Rejects all changes made to the Record since either creation, or the last commit operation.
8313 * Modified fields are reverted to their original values.
8315 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8316 * of reject operations.
8318 reject : function(){
8319 var m = this.modified;
8321 if(typeof m[n] != "function"){
8322 this.data[n] = m[n];
8326 delete this.modified;
8327 this.editing = false;
8329 this.store.afterReject(this);
8334 * Usually called by the {@link Roo.data.Store} which owns the Record.
8335 * Commits all changes made to the Record since either creation, or the last commit operation.
8337 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8338 * of commit operations.
8340 commit : function(){
8342 delete this.modified;
8343 this.editing = false;
8345 this.store.afterCommit(this);
8350 hasError : function(){
8351 return this.error != null;
8355 clearError : function(){
8360 * Creates a copy of this record.
8361 * @param {String} id (optional) A new record id if you don't want to use this record's id
8364 copy : function(newId) {
8365 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8369 * Ext JS Library 1.1.1
8370 * Copyright(c) 2006-2007, Ext JS, LLC.
8372 * Originally Released Under LGPL - original licence link has changed is not relivant.
8375 * <script type="text/javascript">
8381 * @class Roo.data.Store
8382 * @extends Roo.util.Observable
8383 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8384 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8386 * 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
8387 * has no knowledge of the format of the data returned by the Proxy.<br>
8389 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8390 * instances from the data object. These records are cached and made available through accessor functions.
8392 * Creates a new Store.
8393 * @param {Object} config A config object containing the objects needed for the Store to access data,
8394 * and read the data into Records.
8396 Roo.data.Store = function(config){
8397 this.data = new Roo.util.MixedCollection(false);
8398 this.data.getKey = function(o){
8401 this.baseParams = {};
8408 "multisort" : "_multisort"
8411 if(config && config.data){
8412 this.inlineData = config.data;
8416 Roo.apply(this, config);
8418 if(this.reader){ // reader passed
8419 this.reader = Roo.factory(this.reader, Roo.data);
8420 this.reader.xmodule = this.xmodule || false;
8421 if(!this.recordType){
8422 this.recordType = this.reader.recordType;
8424 if(this.reader.onMetaChange){
8425 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8429 if(this.recordType){
8430 this.fields = this.recordType.prototype.fields;
8436 * @event datachanged
8437 * Fires when the data cache has changed, and a widget which is using this Store
8438 * as a Record cache should refresh its view.
8439 * @param {Store} this
8444 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8445 * @param {Store} this
8446 * @param {Object} meta The JSON metadata
8451 * Fires when Records have been added to the Store
8452 * @param {Store} this
8453 * @param {Roo.data.Record[]} records The array of Records added
8454 * @param {Number} index The index at which the record(s) were added
8459 * Fires when a Record has been removed from the Store
8460 * @param {Store} this
8461 * @param {Roo.data.Record} record The Record that was removed
8462 * @param {Number} index The index at which the record was removed
8467 * Fires when a Record has been updated
8468 * @param {Store} this
8469 * @param {Roo.data.Record} record The Record that was updated
8470 * @param {String} operation The update operation being performed. Value may be one of:
8472 Roo.data.Record.EDIT
8473 Roo.data.Record.REJECT
8474 Roo.data.Record.COMMIT
8480 * Fires when the data cache has been cleared.
8481 * @param {Store} this
8486 * Fires before a request is made for a new data object. If the beforeload handler returns false
8487 * the load action will be canceled.
8488 * @param {Store} this
8489 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8493 * @event beforeloadadd
8494 * Fires after a new set of Records has been loaded.
8495 * @param {Store} this
8496 * @param {Roo.data.Record[]} records The Records that were loaded
8497 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8499 beforeloadadd : true,
8502 * Fires after a new set of Records has been loaded, before they are added to the store.
8503 * @param {Store} this
8504 * @param {Roo.data.Record[]} records The Records that were loaded
8505 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8506 * @params {Object} return from reader
8510 * @event loadexception
8511 * Fires if an exception occurs in the Proxy during loading.
8512 * Called with the signature of the Proxy's "loadexception" event.
8513 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8516 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8517 * @param {Object} load options
8518 * @param {Object} jsonData from your request (normally this contains the Exception)
8520 loadexception : true
8524 this.proxy = Roo.factory(this.proxy, Roo.data);
8525 this.proxy.xmodule = this.xmodule || false;
8526 this.relayEvents(this.proxy, ["loadexception"]);
8528 this.sortToggle = {};
8529 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8531 Roo.data.Store.superclass.constructor.call(this);
8533 if(this.inlineData){
8534 this.loadData(this.inlineData);
8535 delete this.inlineData;
8539 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8541 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8542 * without a remote query - used by combo/forms at present.
8546 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8549 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8552 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8553 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8556 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8557 * on any HTTP request
8560 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8563 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8567 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8568 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8573 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8574 * loaded or when a record is removed. (defaults to false).
8576 pruneModifiedRecords : false,
8582 * Add Records to the Store and fires the add event.
8583 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8585 add : function(records){
8586 records = [].concat(records);
8587 for(var i = 0, len = records.length; i < len; i++){
8588 records[i].join(this);
8590 var index = this.data.length;
8591 this.data.addAll(records);
8592 this.fireEvent("add", this, records, index);
8596 * Remove a Record from the Store and fires the remove event.
8597 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8599 remove : function(record){
8600 var index = this.data.indexOf(record);
8601 this.data.removeAt(index);
8602 if(this.pruneModifiedRecords){
8603 this.modified.remove(record);
8605 this.fireEvent("remove", this, record, index);
8609 * Remove all Records from the Store and fires the clear event.
8611 removeAll : function(){
8613 if(this.pruneModifiedRecords){
8616 this.fireEvent("clear", this);
8620 * Inserts Records to the Store at the given index and fires the add event.
8621 * @param {Number} index The start index at which to insert the passed Records.
8622 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8624 insert : function(index, records){
8625 records = [].concat(records);
8626 for(var i = 0, len = records.length; i < len; i++){
8627 this.data.insert(index, records[i]);
8628 records[i].join(this);
8630 this.fireEvent("add", this, records, index);
8634 * Get the index within the cache of the passed Record.
8635 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8636 * @return {Number} The index of the passed Record. Returns -1 if not found.
8638 indexOf : function(record){
8639 return this.data.indexOf(record);
8643 * Get the index within the cache of the Record with the passed id.
8644 * @param {String} id The id of the Record to find.
8645 * @return {Number} The index of the Record. Returns -1 if not found.
8647 indexOfId : function(id){
8648 return this.data.indexOfKey(id);
8652 * Get the Record with the specified id.
8653 * @param {String} id The id of the Record to find.
8654 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8656 getById : function(id){
8657 return this.data.key(id);
8661 * Get the Record at the specified index.
8662 * @param {Number} index The index of the Record to find.
8663 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8665 getAt : function(index){
8666 return this.data.itemAt(index);
8670 * Returns a range of Records between specified indices.
8671 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8672 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8673 * @return {Roo.data.Record[]} An array of Records
8675 getRange : function(start, end){
8676 return this.data.getRange(start, end);
8680 storeOptions : function(o){
8681 o = Roo.apply({}, o);
8684 this.lastOptions = o;
8688 * Loads the Record cache from the configured Proxy using the configured Reader.
8690 * If using remote paging, then the first load call must specify the <em>start</em>
8691 * and <em>limit</em> properties in the options.params property to establish the initial
8692 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8694 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8695 * and this call will return before the new data has been loaded. Perform any post-processing
8696 * in a callback function, or in a "load" event handler.</strong>
8698 * @param {Object} options An object containing properties which control loading options:<ul>
8699 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8700 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8701 * passed the following arguments:<ul>
8702 * <li>r : Roo.data.Record[]</li>
8703 * <li>options: Options object from the load call</li>
8704 * <li>success: Boolean success indicator</li></ul></li>
8705 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8706 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8709 load : function(options){
8710 options = options || {};
8711 if(this.fireEvent("beforeload", this, options) !== false){
8712 this.storeOptions(options);
8713 var p = Roo.apply(options.params || {}, this.baseParams);
8714 // if meta was not loaded from remote source.. try requesting it.
8715 if (!this.reader.metaFromRemote) {
8718 if(this.sortInfo && this.remoteSort){
8719 var pn = this.paramNames;
8720 p[pn["sort"]] = this.sortInfo.field;
8721 p[pn["dir"]] = this.sortInfo.direction;
8723 if (this.multiSort) {
8724 var pn = this.paramNames;
8725 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8728 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8733 * Reloads the Record cache from the configured Proxy using the configured Reader and
8734 * the options from the last load operation performed.
8735 * @param {Object} options (optional) An object containing properties which may override the options
8736 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8737 * the most recently used options are reused).
8739 reload : function(options){
8740 this.load(Roo.applyIf(options||{}, this.lastOptions));
8744 // Called as a callback by the Reader during a load operation.
8745 loadRecords : function(o, options, success){
8746 if(!o || success === false){
8747 if(success !== false){
8748 this.fireEvent("load", this, [], options, o);
8750 if(options.callback){
8751 options.callback.call(options.scope || this, [], options, false);
8755 // if data returned failure - throw an exception.
8756 if (o.success === false) {
8757 // show a message if no listener is registered.
8758 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8759 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8761 // loadmask wil be hooked into this..
8762 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8765 var r = o.records, t = o.totalRecords || r.length;
8767 this.fireEvent("beforeloadadd", this, r, options, o);
8769 if(!options || options.add !== true){
8770 if(this.pruneModifiedRecords){
8773 for(var i = 0, len = r.length; i < len; i++){
8777 this.data = this.snapshot;
8778 delete this.snapshot;
8781 this.data.addAll(r);
8782 this.totalLength = t;
8784 this.fireEvent("datachanged", this);
8786 this.totalLength = Math.max(t, this.data.length+r.length);
8789 this.fireEvent("load", this, r, options, o);
8790 if(options.callback){
8791 options.callback.call(options.scope || this, r, options, true);
8797 * Loads data from a passed data block. A Reader which understands the format of the data
8798 * must have been configured in the constructor.
8799 * @param {Object} data The data block from which to read the Records. The format of the data expected
8800 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8801 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8803 loadData : function(o, append){
8804 var r = this.reader.readRecords(o);
8805 this.loadRecords(r, {add: append}, true);
8809 * Gets the number of cached records.
8811 * <em>If using paging, this may not be the total size of the dataset. If the data object
8812 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8813 * the data set size</em>
8815 getCount : function(){
8816 return this.data.length || 0;
8820 * Gets the total number of records in the dataset as returned by the server.
8822 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8823 * the dataset size</em>
8825 getTotalCount : function(){
8826 return this.totalLength || 0;
8830 * Returns the sort state of the Store as an object with two properties:
8832 field {String} The name of the field by which the Records are sorted
8833 direction {String} The sort order, "ASC" or "DESC"
8836 getSortState : function(){
8837 return this.sortInfo;
8841 applySort : function(){
8842 if(this.sortInfo && !this.remoteSort){
8843 var s = this.sortInfo, f = s.field;
8844 var st = this.fields.get(f).sortType;
8845 var fn = function(r1, r2){
8846 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8847 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8849 this.data.sort(s.direction, fn);
8850 if(this.snapshot && this.snapshot != this.data){
8851 this.snapshot.sort(s.direction, fn);
8857 * Sets the default sort column and order to be used by the next load operation.
8858 * @param {String} fieldName The name of the field to sort by.
8859 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8861 setDefaultSort : function(field, dir){
8862 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8867 * If remote sorting is used, the sort is performed on the server, and the cache is
8868 * reloaded. If local sorting is used, the cache is sorted internally.
8869 * @param {String} fieldName The name of the field to sort by.
8870 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8872 sort : function(fieldName, dir){
8873 var f = this.fields.get(fieldName);
8875 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8877 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8878 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8883 this.sortToggle[f.name] = dir;
8884 this.sortInfo = {field: f.name, direction: dir};
8885 if(!this.remoteSort){
8887 this.fireEvent("datachanged", this);
8889 this.load(this.lastOptions);
8894 * Calls the specified function for each of the Records in the cache.
8895 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8896 * Returning <em>false</em> aborts and exits the iteration.
8897 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8899 each : function(fn, scope){
8900 this.data.each(fn, scope);
8904 * Gets all records modified since the last commit. Modified records are persisted across load operations
8905 * (e.g., during paging).
8906 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8908 getModifiedRecords : function(){
8909 return this.modified;
8913 createFilterFn : function(property, value, anyMatch){
8914 if(!value.exec){ // not a regex
8915 value = String(value);
8916 if(value.length == 0){
8919 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8922 return value.test(r.data[property]);
8927 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8928 * @param {String} property A field on your records
8929 * @param {Number} start The record index to start at (defaults to 0)
8930 * @param {Number} end The last record index to include (defaults to length - 1)
8931 * @return {Number} The sum
8933 sum : function(property, start, end){
8934 var rs = this.data.items, v = 0;
8936 end = (end || end === 0) ? end : rs.length-1;
8938 for(var i = start; i <= end; i++){
8939 v += (rs[i].data[property] || 0);
8945 * Filter the records by a specified property.
8946 * @param {String} field A field on your records
8947 * @param {String/RegExp} value Either a string that the field
8948 * should start with or a RegExp to test against the field
8949 * @param {Boolean} anyMatch True to match any part not just the beginning
8951 filter : function(property, value, anyMatch){
8952 var fn = this.createFilterFn(property, value, anyMatch);
8953 return fn ? this.filterBy(fn) : this.clearFilter();
8957 * Filter by a function. The specified function will be called with each
8958 * record in this data source. If the function returns true the record is included,
8959 * otherwise it is filtered.
8960 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8961 * @param {Object} scope (optional) The scope of the function (defaults to this)
8963 filterBy : function(fn, scope){
8964 this.snapshot = this.snapshot || this.data;
8965 this.data = this.queryBy(fn, scope||this);
8966 this.fireEvent("datachanged", this);
8970 * Query the records by a specified property.
8971 * @param {String} field A field on your records
8972 * @param {String/RegExp} value Either a string that the field
8973 * should start with or a RegExp to test against the field
8974 * @param {Boolean} anyMatch True to match any part not just the beginning
8975 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8977 query : function(property, value, anyMatch){
8978 var fn = this.createFilterFn(property, value, anyMatch);
8979 return fn ? this.queryBy(fn) : this.data.clone();
8983 * Query by a function. The specified function will be called with each
8984 * record in this data source. If the function returns true the record is included
8986 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8987 * @param {Object} scope (optional) The scope of the function (defaults to this)
8988 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8990 queryBy : function(fn, scope){
8991 var data = this.snapshot || this.data;
8992 return data.filterBy(fn, scope||this);
8996 * Collects unique values for a particular dataIndex from this store.
8997 * @param {String} dataIndex The property to collect
8998 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8999 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9000 * @return {Array} An array of the unique values
9002 collect : function(dataIndex, allowNull, bypassFilter){
9003 var d = (bypassFilter === true && this.snapshot) ?
9004 this.snapshot.items : this.data.items;
9005 var v, sv, r = [], l = {};
9006 for(var i = 0, len = d.length; i < len; i++){
9007 v = d[i].data[dataIndex];
9009 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9018 * Revert to a view of the Record cache with no filtering applied.
9019 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9021 clearFilter : function(suppressEvent){
9022 if(this.snapshot && this.snapshot != this.data){
9023 this.data = this.snapshot;
9024 delete this.snapshot;
9025 if(suppressEvent !== true){
9026 this.fireEvent("datachanged", this);
9032 afterEdit : function(record){
9033 if(this.modified.indexOf(record) == -1){
9034 this.modified.push(record);
9036 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9040 afterReject : function(record){
9041 this.modified.remove(record);
9042 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9046 afterCommit : function(record){
9047 this.modified.remove(record);
9048 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9052 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9053 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9055 commitChanges : function(){
9056 var m = this.modified.slice(0);
9058 for(var i = 0, len = m.length; i < len; i++){
9064 * Cancel outstanding changes on all changed records.
9066 rejectChanges : function(){
9067 var m = this.modified.slice(0);
9069 for(var i = 0, len = m.length; i < len; i++){
9074 onMetaChange : function(meta, rtype, o){
9075 this.recordType = rtype;
9076 this.fields = rtype.prototype.fields;
9077 delete this.snapshot;
9078 this.sortInfo = meta.sortInfo || this.sortInfo;
9080 this.fireEvent('metachange', this, this.reader.meta);
9083 moveIndex : function(data, type)
9085 var index = this.indexOf(data);
9087 var newIndex = index + type;
9091 this.insert(newIndex, data);
9096 * Ext JS Library 1.1.1
9097 * Copyright(c) 2006-2007, Ext JS, LLC.
9099 * Originally Released Under LGPL - original licence link has changed is not relivant.
9102 * <script type="text/javascript">
9106 * @class Roo.data.SimpleStore
9107 * @extends Roo.data.Store
9108 * Small helper class to make creating Stores from Array data easier.
9109 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9110 * @cfg {Array} fields An array of field definition objects, or field name strings.
9111 * @cfg {Array} data The multi-dimensional array of data
9113 * @param {Object} config
9115 Roo.data.SimpleStore = function(config){
9116 Roo.data.SimpleStore.superclass.constructor.call(this, {
9118 reader: new Roo.data.ArrayReader({
9121 Roo.data.Record.create(config.fields)
9123 proxy : new Roo.data.MemoryProxy(config.data)
9127 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
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">
9140 * @extends Roo.data.Store
9141 * @class Roo.data.JsonStore
9142 * Small helper class to make creating Stores for JSON data easier. <br/>
9144 var store = new Roo.data.JsonStore({
9145 url: 'get-images.php',
9147 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9150 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9151 * JsonReader and HttpProxy (unless inline data is provided).</b>
9152 * @cfg {Array} fields An array of field definition objects, or field name strings.
9154 * @param {Object} config
9156 Roo.data.JsonStore = function(c){
9157 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9158 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9159 reader: new Roo.data.JsonReader(c, c.fields)
9162 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9164 * Ext JS Library 1.1.1
9165 * Copyright(c) 2006-2007, Ext JS, LLC.
9167 * Originally Released Under LGPL - original licence link has changed is not relivant.
9170 * <script type="text/javascript">
9174 Roo.data.Field = function(config){
9175 if(typeof config == "string"){
9176 config = {name: config};
9178 Roo.apply(this, config);
9184 var st = Roo.data.SortTypes;
9185 // named sortTypes are supported, here we look them up
9186 if(typeof this.sortType == "string"){
9187 this.sortType = st[this.sortType];
9190 // set default sortType for strings and dates
9194 this.sortType = st.asUCString;
9197 this.sortType = st.asDate;
9200 this.sortType = st.none;
9205 var stripRe = /[\$,%]/g;
9207 // prebuilt conversion function for this field, instead of
9208 // switching every time we're reading a value
9210 var cv, dateFormat = this.dateFormat;
9215 cv = function(v){ return v; };
9218 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9222 return v !== undefined && v !== null && v !== '' ?
9223 parseInt(String(v).replace(stripRe, ""), 10) : '';
9228 return v !== undefined && v !== null && v !== '' ?
9229 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9234 cv = function(v){ return v === true || v === "true" || v == 1; };
9241 if(v instanceof Date){
9245 if(dateFormat == "timestamp"){
9246 return new Date(v*1000);
9248 return Date.parseDate(v, dateFormat);
9250 var parsed = Date.parse(v);
9251 return parsed ? new Date(parsed) : null;
9260 Roo.data.Field.prototype = {
9268 * Ext JS Library 1.1.1
9269 * Copyright(c) 2006-2007, Ext JS, LLC.
9271 * Originally Released Under LGPL - original licence link has changed is not relivant.
9274 * <script type="text/javascript">
9277 // Base class for reading structured data from a data source. This class is intended to be
9278 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9281 * @class Roo.data.DataReader
9282 * Base class for reading structured data from a data source. This class is intended to be
9283 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9286 Roo.data.DataReader = function(meta, recordType){
9290 this.recordType = recordType instanceof Array ?
9291 Roo.data.Record.create(recordType) : recordType;
9294 Roo.data.DataReader.prototype = {
9296 * Create an empty record
9297 * @param {Object} data (optional) - overlay some values
9298 * @return {Roo.data.Record} record created.
9300 newRow : function(d) {
9302 this.recordType.prototype.fields.each(function(c) {
9304 case 'int' : da[c.name] = 0; break;
9305 case 'date' : da[c.name] = new Date(); break;
9306 case 'float' : da[c.name] = 0.0; break;
9307 case 'boolean' : da[c.name] = false; break;
9308 default : da[c.name] = ""; break;
9312 return new this.recordType(Roo.apply(da, d));
9317 * Ext JS Library 1.1.1
9318 * Copyright(c) 2006-2007, Ext JS, LLC.
9320 * Originally Released Under LGPL - original licence link has changed is not relivant.
9323 * <script type="text/javascript">
9327 * @class Roo.data.DataProxy
9328 * @extends Roo.data.Observable
9329 * This class is an abstract base class for implementations which provide retrieval of
9330 * unformatted data objects.<br>
9332 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9333 * (of the appropriate type which knows how to parse the data object) to provide a block of
9334 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9336 * Custom implementations must implement the load method as described in
9337 * {@link Roo.data.HttpProxy#load}.
9339 Roo.data.DataProxy = function(){
9343 * Fires before a network request is made to retrieve a data object.
9344 * @param {Object} This DataProxy object.
9345 * @param {Object} params The params parameter to the load function.
9350 * Fires before the load method's callback is called.
9351 * @param {Object} This DataProxy object.
9352 * @param {Object} o The data object.
9353 * @param {Object} arg The callback argument object passed to the load function.
9357 * @event loadexception
9358 * Fires if an Exception occurs during data retrieval.
9359 * @param {Object} This DataProxy object.
9360 * @param {Object} o The data object.
9361 * @param {Object} arg The callback argument object passed to the load function.
9362 * @param {Object} e The Exception.
9364 loadexception : true
9366 Roo.data.DataProxy.superclass.constructor.call(this);
9369 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9372 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9376 * Ext JS Library 1.1.1
9377 * Copyright(c) 2006-2007, Ext JS, LLC.
9379 * Originally Released Under LGPL - original licence link has changed is not relivant.
9382 * <script type="text/javascript">
9385 * @class Roo.data.MemoryProxy
9386 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9387 * to the Reader when its load method is called.
9389 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9391 Roo.data.MemoryProxy = function(data){
9395 Roo.data.MemoryProxy.superclass.constructor.call(this);
9399 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9401 * Load data from the requested source (in this case an in-memory
9402 * data object passed to the constructor), read the data object into
9403 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9404 * process that block using the passed callback.
9405 * @param {Object} params This parameter is not used by the MemoryProxy class.
9406 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9407 * object into a block of Roo.data.Records.
9408 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9409 * The function must be passed <ul>
9410 * <li>The Record block object</li>
9411 * <li>The "arg" argument from the load function</li>
9412 * <li>A boolean success indicator</li>
9414 * @param {Object} scope The scope in which to call the callback
9415 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9417 load : function(params, reader, callback, scope, arg){
9418 params = params || {};
9421 result = reader.readRecords(this.data);
9423 this.fireEvent("loadexception", this, arg, null, e);
9424 callback.call(scope, null, arg, false);
9427 callback.call(scope, result, arg, true);
9431 update : function(params, records){
9436 * Ext JS Library 1.1.1
9437 * Copyright(c) 2006-2007, Ext JS, LLC.
9439 * Originally Released Under LGPL - original licence link has changed is not relivant.
9442 * <script type="text/javascript">
9445 * @class Roo.data.HttpProxy
9446 * @extends Roo.data.DataProxy
9447 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9448 * configured to reference a certain URL.<br><br>
9450 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9451 * from which the running page was served.<br><br>
9453 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9455 * Be aware that to enable the browser to parse an XML document, the server must set
9456 * the Content-Type header in the HTTP response to "text/xml".
9458 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9459 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9460 * will be used to make the request.
9462 Roo.data.HttpProxy = function(conn){
9463 Roo.data.HttpProxy.superclass.constructor.call(this);
9464 // is conn a conn config or a real conn?
9466 this.useAjax = !conn || !conn.events;
9470 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9471 // thse are take from connection...
9474 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9477 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9478 * extra parameters to each request made by this object. (defaults to undefined)
9481 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9482 * to each request made by this object. (defaults to undefined)
9485 * @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)
9488 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9491 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9497 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9501 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9502 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9503 * a finer-grained basis than the DataProxy events.
9505 getConnection : function(){
9506 return this.useAjax ? Roo.Ajax : this.conn;
9510 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9511 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9512 * process that block using the passed callback.
9513 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9514 * for the request to the remote server.
9515 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9516 * object into a block of Roo.data.Records.
9517 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9518 * The function must be passed <ul>
9519 * <li>The Record block object</li>
9520 * <li>The "arg" argument from the load function</li>
9521 * <li>A boolean success indicator</li>
9523 * @param {Object} scope The scope in which to call the callback
9524 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9526 load : function(params, reader, callback, scope, arg){
9527 if(this.fireEvent("beforeload", this, params) !== false){
9529 params : params || {},
9531 callback : callback,
9536 callback : this.loadResponse,
9540 Roo.applyIf(o, this.conn);
9541 if(this.activeRequest){
9542 Roo.Ajax.abort(this.activeRequest);
9544 this.activeRequest = Roo.Ajax.request(o);
9546 this.conn.request(o);
9549 callback.call(scope||this, null, arg, false);
9554 loadResponse : function(o, success, response){
9555 delete this.activeRequest;
9557 this.fireEvent("loadexception", this, o, response);
9558 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9563 result = o.reader.read(response);
9565 this.fireEvent("loadexception", this, o, response, e);
9566 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9570 this.fireEvent("load", this, o, o.request.arg);
9571 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9575 update : function(dataSet){
9580 updateResponse : function(dataSet){
9585 * Ext JS Library 1.1.1
9586 * Copyright(c) 2006-2007, Ext JS, LLC.
9588 * Originally Released Under LGPL - original licence link has changed is not relivant.
9591 * <script type="text/javascript">
9595 * @class Roo.data.ScriptTagProxy
9596 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9597 * other than the originating domain of the running page.<br><br>
9599 * <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
9600 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9602 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9603 * source code that is used as the source inside a <script> tag.<br><br>
9605 * In order for the browser to process the returned data, the server must wrap the data object
9606 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9607 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9608 * depending on whether the callback name was passed:
9611 boolean scriptTag = false;
9612 String cb = request.getParameter("callback");
9615 response.setContentType("text/javascript");
9617 response.setContentType("application/x-json");
9619 Writer out = response.getWriter();
9621 out.write(cb + "(");
9623 out.print(dataBlock.toJsonString());
9630 * @param {Object} config A configuration object.
9632 Roo.data.ScriptTagProxy = function(config){
9633 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9634 Roo.apply(this, config);
9635 this.head = document.getElementsByTagName("head")[0];
9638 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9640 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9642 * @cfg {String} url The URL from which to request the data object.
9645 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9649 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9650 * the server the name of the callback function set up by the load call to process the returned data object.
9651 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9652 * javascript output which calls this named function passing the data object as its only parameter.
9654 callbackParam : "callback",
9656 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9657 * name to the request.
9662 * Load data from the configured URL, read the data object into
9663 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9664 * process that block using the passed callback.
9665 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9666 * for the request to the remote server.
9667 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9668 * object into a block of Roo.data.Records.
9669 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9670 * The function must be passed <ul>
9671 * <li>The Record block object</li>
9672 * <li>The "arg" argument from the load function</li>
9673 * <li>A boolean success indicator</li>
9675 * @param {Object} scope The scope in which to call the callback
9676 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9678 load : function(params, reader, callback, scope, arg){
9679 if(this.fireEvent("beforeload", this, params) !== false){
9681 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9684 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9686 url += "&_dc=" + (new Date().getTime());
9688 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9691 cb : "stcCallback"+transId,
9692 scriptId : "stcScript"+transId,
9696 callback : callback,
9702 window[trans.cb] = function(o){
9703 conn.handleResponse(o, trans);
9706 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9708 if(this.autoAbort !== false){
9712 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9714 var script = document.createElement("script");
9715 script.setAttribute("src", url);
9716 script.setAttribute("type", "text/javascript");
9717 script.setAttribute("id", trans.scriptId);
9718 this.head.appendChild(script);
9722 callback.call(scope||this, null, arg, false);
9727 isLoading : function(){
9728 return this.trans ? true : false;
9732 * Abort the current server request.
9735 if(this.isLoading()){
9736 this.destroyTrans(this.trans);
9741 destroyTrans : function(trans, isLoaded){
9742 this.head.removeChild(document.getElementById(trans.scriptId));
9743 clearTimeout(trans.timeoutId);
9745 window[trans.cb] = undefined;
9747 delete window[trans.cb];
9750 // if hasn't been loaded, wait for load to remove it to prevent script error
9751 window[trans.cb] = function(){
9752 window[trans.cb] = undefined;
9754 delete window[trans.cb];
9761 handleResponse : function(o, trans){
9763 this.destroyTrans(trans, true);
9766 result = trans.reader.readRecords(o);
9768 this.fireEvent("loadexception", this, o, trans.arg, e);
9769 trans.callback.call(trans.scope||window, null, trans.arg, false);
9772 this.fireEvent("load", this, o, trans.arg);
9773 trans.callback.call(trans.scope||window, result, trans.arg, true);
9777 handleFailure : function(trans){
9779 this.destroyTrans(trans, false);
9780 this.fireEvent("loadexception", this, null, trans.arg);
9781 trans.callback.call(trans.scope||window, null, trans.arg, false);
9785 * Ext JS Library 1.1.1
9786 * Copyright(c) 2006-2007, Ext JS, LLC.
9788 * Originally Released Under LGPL - original licence link has changed is not relivant.
9791 * <script type="text/javascript">
9795 * @class Roo.data.JsonReader
9796 * @extends Roo.data.DataReader
9797 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9798 * based on mappings in a provided Roo.data.Record constructor.
9800 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9801 * in the reply previously.
9806 var RecordDef = Roo.data.Record.create([
9807 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9808 {name: 'occupation'} // This field will use "occupation" as the mapping.
9810 var myReader = new Roo.data.JsonReader({
9811 totalProperty: "results", // The property which contains the total dataset size (optional)
9812 root: "rows", // The property which contains an Array of row objects
9813 id: "id" // The property within each row object that provides an ID for the record (optional)
9817 * This would consume a JSON file like this:
9819 { 'results': 2, 'rows': [
9820 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9821 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9824 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9825 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9826 * paged from the remote server.
9827 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9828 * @cfg {String} root name of the property which contains the Array of row objects.
9829 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9831 * Create a new JsonReader
9832 * @param {Object} meta Metadata configuration options
9833 * @param {Object} recordType Either an Array of field definition objects,
9834 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9836 Roo.data.JsonReader = function(meta, recordType){
9839 // set some defaults:
9841 totalProperty: 'total',
9842 successProperty : 'success',
9847 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9849 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9852 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9853 * Used by Store query builder to append _requestMeta to params.
9856 metaFromRemote : false,
9858 * This method is only used by a DataProxy which has retrieved data from a remote server.
9859 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9860 * @return {Object} data A data block which is used by an Roo.data.Store object as
9861 * a cache of Roo.data.Records.
9863 read : function(response){
9864 var json = response.responseText;
9866 var o = /* eval:var:o */ eval("("+json+")");
9868 throw {message: "JsonReader.read: Json object not found"};
9874 this.metaFromRemote = true;
9875 this.meta = o.metaData;
9876 this.recordType = Roo.data.Record.create(o.metaData.fields);
9877 this.onMetaChange(this.meta, this.recordType, o);
9879 return this.readRecords(o);
9882 // private function a store will implement
9883 onMetaChange : function(meta, recordType, o){
9890 simpleAccess: function(obj, subsc) {
9897 getJsonAccessor: function(){
9899 return function(expr) {
9901 return(re.test(expr))
9902 ? new Function("obj", "return obj." + expr)
9912 * Create a data block containing Roo.data.Records from an XML document.
9913 * @param {Object} o An object which contains an Array of row objects in the property specified
9914 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9915 * which contains the total size of the dataset.
9916 * @return {Object} data A data block which is used by an Roo.data.Store object as
9917 * a cache of Roo.data.Records.
9919 readRecords : function(o){
9921 * After any data loads, the raw JSON data is available for further custom processing.
9925 var s = this.meta, Record = this.recordType,
9926 f = Record.prototype.fields, fi = f.items, fl = f.length;
9928 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9930 if(s.totalProperty) {
9931 this.getTotal = this.getJsonAccessor(s.totalProperty);
9933 if(s.successProperty) {
9934 this.getSuccess = this.getJsonAccessor(s.successProperty);
9936 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9938 var g = this.getJsonAccessor(s.id);
9939 this.getId = function(rec) {
9941 return (r === undefined || r === "") ? null : r;
9944 this.getId = function(){return null;};
9947 for(var jj = 0; jj < fl; jj++){
9949 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9950 this.ef[jj] = this.getJsonAccessor(map);
9954 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9955 if(s.totalProperty){
9956 var vt = parseInt(this.getTotal(o), 10);
9961 if(s.successProperty){
9962 var vs = this.getSuccess(o);
9963 if(vs === false || vs === 'false'){
9968 for(var i = 0; i < c; i++){
9971 var id = this.getId(n);
9972 for(var j = 0; j < fl; j++){
9974 var v = this.ef[j](n);
9976 Roo.log('missing convert for ' + f.name);
9980 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9982 var record = new Record(values, id);
9984 records[i] = record;
9990 totalRecords : totalRecords
9995 * Ext JS Library 1.1.1
9996 * Copyright(c) 2006-2007, Ext JS, LLC.
9998 * Originally Released Under LGPL - original licence link has changed is not relivant.
10001 * <script type="text/javascript">
10005 * @class Roo.data.ArrayReader
10006 * @extends Roo.data.DataReader
10007 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10008 * Each element of that Array represents a row of data fields. The
10009 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10010 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10014 var RecordDef = Roo.data.Record.create([
10015 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10016 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10018 var myReader = new Roo.data.ArrayReader({
10019 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10023 * This would consume an Array like this:
10025 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10027 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10029 * Create a new JsonReader
10030 * @param {Object} meta Metadata configuration options.
10031 * @param {Object} recordType Either an Array of field definition objects
10032 * as specified to {@link Roo.data.Record#create},
10033 * or an {@link Roo.data.Record} object
10034 * created using {@link Roo.data.Record#create}.
10036 Roo.data.ArrayReader = function(meta, recordType){
10037 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10040 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10042 * Create a data block containing Roo.data.Records from an XML document.
10043 * @param {Object} o An Array of row objects which represents the dataset.
10044 * @return {Object} data A data block which is used by an Roo.data.Store object as
10045 * a cache of Roo.data.Records.
10047 readRecords : function(o){
10048 var sid = this.meta ? this.meta.id : null;
10049 var recordType = this.recordType, fields = recordType.prototype.fields;
10052 for(var i = 0; i < root.length; i++){
10055 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10056 for(var j = 0, jlen = fields.length; j < jlen; j++){
10057 var f = fields.items[j];
10058 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10059 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10061 values[f.name] = v;
10063 var record = new recordType(values, id);
10065 records[records.length] = record;
10069 totalRecords : records.length
10078 * @class Roo.bootstrap.ComboBox
10079 * @extends Roo.bootstrap.TriggerField
10080 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10081 * @cfg {Boolean} append (true|false) default false
10082 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10083 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10084 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10085 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10087 * Create a new ComboBox.
10088 * @param {Object} config Configuration options
10090 Roo.bootstrap.ComboBox = function(config){
10091 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10095 * Fires when the dropdown list is expanded
10096 * @param {Roo.bootstrap.ComboBox} combo This combo box
10101 * Fires when the dropdown list is collapsed
10102 * @param {Roo.bootstrap.ComboBox} combo This combo box
10106 * @event beforeselect
10107 * Fires before a list item is selected. Return false to cancel the selection.
10108 * @param {Roo.bootstrap.ComboBox} combo This combo box
10109 * @param {Roo.data.Record} record The data record returned from the underlying store
10110 * @param {Number} index The index of the selected item in the dropdown list
10112 'beforeselect' : true,
10115 * Fires when a list item is selected
10116 * @param {Roo.bootstrap.ComboBox} combo This combo box
10117 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10118 * @param {Number} index The index of the selected item in the dropdown list
10122 * @event beforequery
10123 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10124 * The event object passed has these properties:
10125 * @param {Roo.bootstrap.ComboBox} combo This combo box
10126 * @param {String} query The query
10127 * @param {Boolean} forceAll true to force "all" query
10128 * @param {Boolean} cancel true to cancel the query
10129 * @param {Object} e The query event object
10131 'beforequery': true,
10134 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10135 * @param {Roo.bootstrap.ComboBox} combo This combo box
10140 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10141 * @param {Roo.bootstrap.ComboBox} combo This combo box
10142 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10147 * Fires when the remove value from the combobox array
10148 * @param {Roo.bootstrap.ComboBox} combo This combo box
10155 this.tickItems = [];
10157 this.selectedIndex = -1;
10158 if(this.mode == 'local'){
10159 if(config.queryDelay === undefined){
10160 this.queryDelay = 10;
10162 if(config.minChars === undefined){
10168 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10171 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10172 * rendering into an Roo.Editor, defaults to false)
10175 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10176 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10179 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10182 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10183 * the dropdown list (defaults to undefined, with no header element)
10187 * @cfg {String/Roo.Template} tpl The template to use to render the output
10191 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10193 listWidth: undefined,
10195 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10196 * mode = 'remote' or 'text' if mode = 'local')
10198 displayField: undefined,
10200 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10201 * mode = 'remote' or 'value' if mode = 'local').
10202 * Note: use of a valueField requires the user make a selection
10203 * in order for a value to be mapped.
10205 valueField: undefined,
10209 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10210 * field's data value (defaults to the underlying DOM element's name)
10212 hiddenName: undefined,
10214 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10218 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10220 selectedClass: 'active',
10223 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10227 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10228 * anchor positions (defaults to 'tl-bl')
10230 listAlign: 'tl-bl?',
10232 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10236 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10237 * query specified by the allQuery config option (defaults to 'query')
10239 triggerAction: 'query',
10241 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10242 * (defaults to 4, does not apply if editable = false)
10246 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10247 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10251 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10252 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10256 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10257 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10261 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10262 * when editable = true (defaults to false)
10264 selectOnFocus:false,
10266 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10268 queryParam: 'query',
10270 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10271 * when mode = 'remote' (defaults to 'Loading...')
10273 loadingText: 'Loading...',
10275 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10279 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10283 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10284 * traditional select (defaults to true)
10288 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10292 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10296 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10297 * listWidth has a higher value)
10301 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10302 * allow the user to set arbitrary text into the field (defaults to false)
10304 forceSelection:false,
10306 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10307 * if typeAhead = true (defaults to 250)
10309 typeAheadDelay : 250,
10311 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10312 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10314 valueNotFoundText : undefined,
10316 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10318 blockFocus : false,
10321 * @cfg {Boolean} disableClear Disable showing of clear button.
10323 disableClear : false,
10325 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10327 alwaysQuery : false,
10330 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10344 btnPosition : 'right',
10345 triggerList : true,
10346 // element that contains real text value.. (when hidden is used..)
10348 getAutoCreate : function()
10355 if(!this.tickable){
10356 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10361 * ComboBox with tickable selections
10364 var align = this.labelAlign || this.parentLabelAlign();
10367 cls : 'form-group roo-combobox-tickable' //input-group
10373 cls : 'tickable-buttons',
10378 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10385 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10392 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10399 Roo.each(buttons.cn, function(c){
10401 c.cls += ' btn-' + _this.size;
10404 if (_this.disabled) {
10415 cls: 'form-hidden-field'
10419 cls: 'select2-choices',
10423 cls: 'select2-search-field',
10435 cls: 'select2-container input-group select2-container-multi',
10440 // cls: 'typeahead typeahead-long dropdown-menu',
10441 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10446 if (align ==='left' && this.fieldLabel.length) {
10448 Roo.log("left and has label");
10454 cls : 'control-label col-sm-' + this.labelWidth,
10455 html : this.fieldLabel
10459 cls : "col-sm-" + (12 - this.labelWidth),
10466 } else if ( this.fieldLabel.length) {
10472 //cls : 'input-group-addon',
10473 html : this.fieldLabel
10483 Roo.log(" no label && no align");
10490 ['xs','sm','md','lg'].map(function(size){
10491 if (settings[size]) {
10492 cfg.cls += ' col-' + size + '-' + settings[size];
10501 initEvents: function()
10505 throw "can not find store for combo";
10507 this.store = Roo.factory(this.store, Roo.data);
10510 this.initTickableEvents();
10514 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10516 if(this.hiddenName){
10518 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10520 this.hiddenField.dom.value =
10521 this.hiddenValue !== undefined ? this.hiddenValue :
10522 this.value !== undefined ? this.value : '';
10524 // prevent input submission
10525 this.el.dom.removeAttribute('name');
10526 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10531 // this.el.dom.setAttribute('autocomplete', 'off');
10534 var cls = 'x-combo-list';
10536 //this.list = new Roo.Layer({
10537 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10543 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10544 _this.list.setWidth(lw);
10547 this.list.on('mouseover', this.onViewOver, this);
10548 this.list.on('mousemove', this.onViewMove, this);
10550 this.list.on('scroll', this.onViewScroll, this);
10553 this.list.swallowEvent('mousewheel');
10554 this.assetHeight = 0;
10557 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10558 this.assetHeight += this.header.getHeight();
10561 this.innerList = this.list.createChild({cls:cls+'-inner'});
10562 this.innerList.on('mouseover', this.onViewOver, this);
10563 this.innerList.on('mousemove', this.onViewMove, this);
10564 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10566 if(this.allowBlank && !this.pageSize && !this.disableClear){
10567 this.footer = this.list.createChild({cls:cls+'-ft'});
10568 this.pageTb = new Roo.Toolbar(this.footer);
10572 this.footer = this.list.createChild({cls:cls+'-ft'});
10573 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10574 {pageSize: this.pageSize});
10578 if (this.pageTb && this.allowBlank && !this.disableClear) {
10580 this.pageTb.add(new Roo.Toolbar.Fill(), {
10581 cls: 'x-btn-icon x-btn-clear',
10583 handler: function()
10586 _this.clearValue();
10587 _this.onSelect(false, -1);
10592 this.assetHeight += this.footer.getHeight();
10597 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10600 this.view = new Roo.View(this.list, this.tpl, {
10601 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10603 //this.view.wrapEl.setDisplayed(false);
10604 this.view.on('click', this.onViewClick, this);
10608 this.store.on('beforeload', this.onBeforeLoad, this);
10609 this.store.on('load', this.onLoad, this);
10610 this.store.on('loadexception', this.onLoadException, this);
10612 if(this.resizable){
10613 this.resizer = new Roo.Resizable(this.list, {
10614 pinned:true, handles:'se'
10616 this.resizer.on('resize', function(r, w, h){
10617 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10618 this.listWidth = w;
10619 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10620 this.restrictHeight();
10622 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10625 if(!this.editable){
10626 this.editable = true;
10627 this.setEditable(false);
10632 if (typeof(this.events.add.listeners) != 'undefined') {
10634 this.addicon = this.wrap.createChild(
10635 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10637 this.addicon.on('click', function(e) {
10638 this.fireEvent('add', this);
10641 if (typeof(this.events.edit.listeners) != 'undefined') {
10643 this.editicon = this.wrap.createChild(
10644 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10645 if (this.addicon) {
10646 this.editicon.setStyle('margin-left', '40px');
10648 this.editicon.on('click', function(e) {
10650 // we fire even if inothing is selected..
10651 this.fireEvent('edit', this, this.lastData );
10657 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10658 "up" : function(e){
10659 this.inKeyMode = true;
10663 "down" : function(e){
10664 if(!this.isExpanded()){
10665 this.onTriggerClick();
10667 this.inKeyMode = true;
10672 "enter" : function(e){
10673 // this.onViewClick();
10677 if(this.fireEvent("specialkey", this, e)){
10678 this.onViewClick(false);
10684 "esc" : function(e){
10688 "tab" : function(e){
10691 if(this.fireEvent("specialkey", this, e)){
10692 this.onViewClick(false);
10700 doRelay : function(foo, bar, hname){
10701 if(hname == 'down' || this.scope.isExpanded()){
10702 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10711 this.queryDelay = Math.max(this.queryDelay || 10,
10712 this.mode == 'local' ? 10 : 250);
10715 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10717 if(this.typeAhead){
10718 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10720 if(this.editable !== false){
10721 this.inputEl().on("keyup", this.onKeyUp, this);
10723 if(this.forceSelection){
10724 this.inputEl().on('blur', this.doForce, this);
10728 this.choices = this.el.select('ul.select2-choices', true).first();
10729 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10733 initTickableEvents: function()
10737 if(this.hiddenName){
10739 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10741 this.hiddenField.dom.value =
10742 this.hiddenValue !== undefined ? this.hiddenValue :
10743 this.value !== undefined ? this.value : '';
10745 // prevent input submission
10746 this.el.dom.removeAttribute('name');
10747 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10752 // this.list = this.el.select('ul.dropdown-menu',true).first();
10754 this.choices = this.el.select('ul.select2-choices', true).first();
10755 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10756 if(this.triggerList){
10757 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10760 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10761 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10763 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10764 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10766 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10767 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10769 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10770 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10771 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10774 this.cancelBtn.hide();
10779 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10780 _this.list.setWidth(lw);
10783 this.list.on('mouseover', this.onViewOver, this);
10784 this.list.on('mousemove', this.onViewMove, this);
10786 this.list.on('scroll', this.onViewScroll, this);
10789 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>';
10792 this.view = new Roo.View(this.list, this.tpl, {
10793 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10796 //this.view.wrapEl.setDisplayed(false);
10797 this.view.on('click', this.onViewClick, this);
10801 this.store.on('beforeload', this.onBeforeLoad, this);
10802 this.store.on('load', this.onLoad, this);
10803 this.store.on('loadexception', this.onLoadException, this);
10805 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10806 // "up" : function(e){
10807 // this.inKeyMode = true;
10808 // this.selectPrev();
10811 // "down" : function(e){
10812 // if(!this.isExpanded()){
10813 // this.onTriggerClick();
10815 // this.inKeyMode = true;
10816 // this.selectNext();
10820 // "enter" : function(e){
10821 //// this.onViewClick();
10823 // this.collapse();
10825 // if(this.fireEvent("specialkey", this, e)){
10826 // this.onViewClick(false);
10832 // "esc" : function(e){
10833 // this.collapse();
10836 // "tab" : function(e){
10837 // this.collapse();
10839 // if(this.fireEvent("specialkey", this, e)){
10840 // this.onViewClick(false);
10848 // doRelay : function(foo, bar, hname){
10849 // if(hname == 'down' || this.scope.isExpanded()){
10850 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10855 // forceKeyDown: true
10859 this.queryDelay = Math.max(this.queryDelay || 10,
10860 this.mode == 'local' ? 10 : 250);
10863 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10865 if(this.typeAhead){
10866 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10870 onDestroy : function(){
10872 this.view.setStore(null);
10873 this.view.el.removeAllListeners();
10874 this.view.el.remove();
10875 this.view.purgeListeners();
10878 this.list.dom.innerHTML = '';
10882 this.store.un('beforeload', this.onBeforeLoad, this);
10883 this.store.un('load', this.onLoad, this);
10884 this.store.un('loadexception', this.onLoadException, this);
10886 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10890 fireKey : function(e){
10891 if(e.isNavKeyPress() && !this.list.isVisible()){
10892 this.fireEvent("specialkey", this, e);
10897 onResize: function(w, h){
10898 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10900 // if(typeof w != 'number'){
10901 // // we do not handle it!?!?
10904 // var tw = this.trigger.getWidth();
10905 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10906 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10908 // this.inputEl().setWidth( this.adjustWidth('input', x));
10910 // //this.trigger.setStyle('left', x+'px');
10912 // if(this.list && this.listWidth === undefined){
10913 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10914 // this.list.setWidth(lw);
10915 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10923 * Allow or prevent the user from directly editing the field text. If false is passed,
10924 * the user will only be able to select from the items defined in the dropdown list. This method
10925 * is the runtime equivalent of setting the 'editable' config option at config time.
10926 * @param {Boolean} value True to allow the user to directly edit the field text
10928 setEditable : function(value){
10929 if(value == this.editable){
10932 this.editable = value;
10934 this.inputEl().dom.setAttribute('readOnly', true);
10935 this.inputEl().on('mousedown', this.onTriggerClick, this);
10936 this.inputEl().addClass('x-combo-noedit');
10938 this.inputEl().dom.setAttribute('readOnly', false);
10939 this.inputEl().un('mousedown', this.onTriggerClick, this);
10940 this.inputEl().removeClass('x-combo-noedit');
10946 onBeforeLoad : function(combo,opts){
10947 if(!this.hasFocus){
10951 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10953 // this.restrictHeight();
10954 this.selectedIndex = -1;
10958 onLoad : function(){
10960 this.hasQuery = false;
10962 if(!this.hasFocus){
10966 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10967 this.loading.hide();
10970 if(this.store.getCount() > 0){
10972 // this.restrictHeight();
10973 if(this.lastQuery == this.allQuery){
10974 if(this.editable && !this.tickable){
10975 this.inputEl().dom.select();
10977 if(!this.selectByValue(this.value, true) && this.autoFocus){
10978 this.select(0, true);
10981 if(this.autoFocus){
10984 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10985 this.taTask.delay(this.typeAheadDelay);
10989 this.onEmptyResults();
10995 onLoadException : function()
10997 this.hasQuery = false;
10999 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11000 this.loading.hide();
11004 Roo.log(this.store.reader.jsonData);
11005 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11007 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11013 onTypeAhead : function(){
11014 if(this.store.getCount() > 0){
11015 var r = this.store.getAt(0);
11016 var newValue = r.data[this.displayField];
11017 var len = newValue.length;
11018 var selStart = this.getRawValue().length;
11020 if(selStart != len){
11021 this.setRawValue(newValue);
11022 this.selectText(selStart, newValue.length);
11028 onSelect : function(record, index){
11030 if(this.fireEvent('beforeselect', this, record, index) !== false){
11032 this.setFromData(index > -1 ? record.data : false);
11035 this.fireEvent('select', this, record, index);
11040 * Returns the currently selected field value or empty string if no value is set.
11041 * @return {String} value The selected value
11043 getValue : function(){
11046 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11049 if(this.valueField){
11050 return typeof this.value != 'undefined' ? this.value : '';
11052 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11057 * Clears any text/value currently set in the field
11059 clearValue : function(){
11060 if(this.hiddenField){
11061 this.hiddenField.dom.value = '';
11064 this.setRawValue('');
11065 this.lastSelectionText = '';
11070 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11071 * will be displayed in the field. If the value does not match the data value of an existing item,
11072 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11073 * Otherwise the field will be blank (although the value will still be set).
11074 * @param {String} value The value to match
11076 setValue : function(v){
11083 if(this.valueField){
11084 var r = this.findRecord(this.valueField, v);
11086 text = r.data[this.displayField];
11087 }else if(this.valueNotFoundText !== undefined){
11088 text = this.valueNotFoundText;
11091 this.lastSelectionText = text;
11092 if(this.hiddenField){
11093 this.hiddenField.dom.value = v;
11095 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11099 * @property {Object} the last set data for the element
11104 * Sets the value of the field based on a object which is related to the record format for the store.
11105 * @param {Object} value the value to set as. or false on reset?
11107 setFromData : function(o){
11110 if(typeof o.display_name !== 'string'){
11111 for(var i=0;i<o.display_name.length;i++){
11112 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11120 var dv = ''; // display value
11121 var vv = ''; // value value..
11123 if (this.displayField) {
11124 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11126 // this is an error condition!!!
11127 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11130 if(this.valueField){
11131 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11134 if(this.hiddenField){
11135 this.hiddenField.dom.value = vv;
11137 this.lastSelectionText = dv;
11138 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11142 // no hidden field.. - we store the value in 'value', but still display
11143 // display field!!!!
11144 this.lastSelectionText = dv;
11145 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11151 reset : function(){
11152 // overridden so that last data is reset..
11153 this.setValue(this.originalValue);
11154 this.clearInvalid();
11155 this.lastData = false;
11157 this.view.clearSelections();
11161 findRecord : function(prop, value){
11163 if(this.store.getCount() > 0){
11164 this.store.each(function(r){
11165 if(r.data[prop] == value){
11175 getName: function()
11177 // returns hidden if it's set..
11178 if (!this.rendered) {return ''};
11179 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11183 onViewMove : function(e, t){
11184 this.inKeyMode = false;
11188 onViewOver : function(e, t){
11189 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11192 var item = this.view.findItemFromChild(t);
11195 var index = this.view.indexOf(item);
11196 this.select(index, false);
11201 onViewClick : function(view, doFocus, el, e)
11203 var index = this.view.getSelectedIndexes()[0];
11205 var r = this.store.getAt(index);
11209 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11216 Roo.each(this.tickItems, function(v,k){
11218 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11219 _this.tickItems.splice(k, 1);
11229 this.tickItems.push(r.data);
11234 this.onSelect(r, index);
11236 if(doFocus !== false && !this.blockFocus){
11237 this.inputEl().focus();
11242 restrictHeight : function(){
11243 //this.innerList.dom.style.height = '';
11244 //var inner = this.innerList.dom;
11245 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11246 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11247 //this.list.beginUpdate();
11248 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11249 this.list.alignTo(this.inputEl(), this.listAlign);
11250 this.list.alignTo(this.inputEl(), this.listAlign);
11251 //this.list.endUpdate();
11255 onEmptyResults : function(){
11260 * Returns true if the dropdown list is expanded, else false.
11262 isExpanded : function(){
11263 return this.list.isVisible();
11267 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11268 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11269 * @param {String} value The data value of the item to select
11270 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11271 * selected item if it is not currently in view (defaults to true)
11272 * @return {Boolean} True if the value matched an item in the list, else false
11274 selectByValue : function(v, scrollIntoView){
11275 if(v !== undefined && v !== null){
11276 var r = this.findRecord(this.valueField || this.displayField, v);
11278 this.select(this.store.indexOf(r), scrollIntoView);
11286 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11287 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11288 * @param {Number} index The zero-based index of the list item to select
11289 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11290 * selected item if it is not currently in view (defaults to true)
11292 select : function(index, scrollIntoView){
11293 this.selectedIndex = index;
11294 this.view.select(index);
11295 if(scrollIntoView !== false){
11296 var el = this.view.getNode(index);
11297 if(el && !this.multiple && !this.tickable){
11298 this.list.scrollChildIntoView(el, false);
11304 selectNext : function(){
11305 var ct = this.store.getCount();
11307 if(this.selectedIndex == -1){
11309 }else if(this.selectedIndex < ct-1){
11310 this.select(this.selectedIndex+1);
11316 selectPrev : function(){
11317 var ct = this.store.getCount();
11319 if(this.selectedIndex == -1){
11321 }else if(this.selectedIndex != 0){
11322 this.select(this.selectedIndex-1);
11328 onKeyUp : function(e){
11329 if(this.editable !== false && !e.isSpecialKey()){
11330 this.lastKey = e.getKey();
11331 this.dqTask.delay(this.queryDelay);
11336 validateBlur : function(){
11337 return !this.list || !this.list.isVisible();
11341 initQuery : function(){
11342 this.doQuery(this.getRawValue());
11346 doForce : function(){
11347 if(this.inputEl().dom.value.length > 0){
11348 this.inputEl().dom.value =
11349 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11355 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11356 * query allowing the query action to be canceled if needed.
11357 * @param {String} query The SQL query to execute
11358 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11359 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11360 * saved in the current store (defaults to false)
11362 doQuery : function(q, forceAll){
11364 if(q === undefined || q === null){
11369 forceAll: forceAll,
11373 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11378 forceAll = qe.forceAll;
11379 if(forceAll === true || (q.length >= this.minChars)){
11381 this.hasQuery = true;
11383 if(this.lastQuery != q || this.alwaysQuery){
11384 this.lastQuery = q;
11385 if(this.mode == 'local'){
11386 this.selectedIndex = -1;
11388 this.store.clearFilter();
11390 this.store.filter(this.displayField, q);
11394 this.store.baseParams[this.queryParam] = q;
11396 var options = {params : this.getParams(q)};
11399 options.add = true;
11400 options.params.start = this.page * this.pageSize;
11403 this.store.load(options);
11405 * this code will make the page width larger, at the beginning, the list not align correctly,
11406 * we should expand the list on onLoad
11407 * so command out it
11412 this.selectedIndex = -1;
11417 this.loadNext = false;
11421 getParams : function(q){
11423 //p[this.queryParam] = q;
11427 p.limit = this.pageSize;
11433 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11435 collapse : function(){
11436 if(!this.isExpanded()){
11440 this.hasFocus = false;
11446 this.cancelBtn.hide();
11447 this.trigger.show();
11450 Roo.get(document).un('mousedown', this.collapseIf, this);
11451 Roo.get(document).un('mousewheel', this.collapseIf, this);
11452 if (!this.editable) {
11453 Roo.get(document).un('keydown', this.listKeyPress, this);
11455 this.fireEvent('collapse', this);
11459 collapseIf : function(e){
11460 var in_combo = e.within(this.el);
11461 var in_list = e.within(this.list);
11462 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11464 if (in_combo || in_list || is_list) {
11465 //e.stopPropagation();
11470 this.onTickableFooterButtonClick(e, false, false);
11478 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11480 expand : function(){
11482 if(this.isExpanded() || !this.hasFocus){
11489 this.restrictHeight();
11493 this.tickItems = Roo.apply([], this.item);
11496 this.cancelBtn.show();
11497 this.trigger.hide();
11501 Roo.get(document).on('mousedown', this.collapseIf, this);
11502 Roo.get(document).on('mousewheel', this.collapseIf, this);
11503 if (!this.editable) {
11504 Roo.get(document).on('keydown', this.listKeyPress, this);
11507 this.fireEvent('expand', this);
11511 // Implements the default empty TriggerField.onTriggerClick function
11512 onTriggerClick : function(e)
11514 Roo.log('trigger click');
11516 if(this.disabled || !this.triggerList){
11521 this.loadNext = false;
11523 if(this.isExpanded()){
11525 if (!this.blockFocus) {
11526 this.inputEl().focus();
11530 this.hasFocus = true;
11531 if(this.triggerAction == 'all') {
11532 this.doQuery(this.allQuery, true);
11534 this.doQuery(this.getRawValue());
11536 if (!this.blockFocus) {
11537 this.inputEl().focus();
11542 onTickableTriggerClick : function(e)
11549 this.loadNext = false;
11550 this.hasFocus = true;
11552 if(this.triggerAction == 'all') {
11553 this.doQuery(this.allQuery, true);
11555 this.doQuery(this.getRawValue());
11559 onSearchFieldClick : function(e)
11561 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11566 this.loadNext = false;
11567 this.hasFocus = true;
11569 if(this.triggerAction == 'all') {
11570 this.doQuery(this.allQuery, true);
11572 this.doQuery(this.getRawValue());
11576 listKeyPress : function(e)
11578 //Roo.log('listkeypress');
11579 // scroll to first matching element based on key pres..
11580 if (e.isSpecialKey()) {
11583 var k = String.fromCharCode(e.getKey()).toUpperCase();
11586 var csel = this.view.getSelectedNodes();
11587 var cselitem = false;
11589 var ix = this.view.indexOf(csel[0]);
11590 cselitem = this.store.getAt(ix);
11591 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11597 this.store.each(function(v) {
11599 // start at existing selection.
11600 if (cselitem.id == v.id) {
11606 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11607 match = this.store.indexOf(v);
11613 if (match === false) {
11614 return true; // no more action?
11617 this.view.select(match);
11618 var sn = Roo.get(this.view.getSelectedNodes()[0])
11619 //sn.scrollIntoView(sn.dom.parentNode, false);
11622 onViewScroll : function(e, t){
11624 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11628 this.hasQuery = true;
11630 this.loading = this.list.select('.loading', true).first();
11632 if(this.loading === null){
11633 this.list.createChild({
11635 cls: 'loading select2-more-results select2-active',
11636 html: 'Loading more results...'
11639 this.loading = this.list.select('.loading', true).first();
11641 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11643 this.loading.hide();
11646 this.loading.show();
11651 this.loadNext = true;
11653 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11658 addItem : function(o)
11660 var dv = ''; // display value
11662 if (this.displayField) {
11663 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11665 // this is an error condition!!!
11666 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11673 var choice = this.choices.createChild({
11675 cls: 'select2-search-choice',
11684 cls: 'select2-search-choice-close',
11689 }, this.searchField);
11691 var close = choice.select('a.select2-search-choice-close', true).first()
11693 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11701 this.inputEl().dom.value = '';
11705 onRemoveItem : function(e, _self, o)
11707 e.preventDefault();
11708 var index = this.item.indexOf(o.data) * 1;
11711 Roo.log('not this item?!');
11715 this.item.splice(index, 1);
11720 this.fireEvent('remove', this, e);
11724 syncValue : function()
11726 if(!this.item.length){
11733 Roo.each(this.item, function(i){
11734 if(_this.valueField){
11735 value.push(i[_this.valueField]);
11742 this.value = value.join(',');
11744 if(this.hiddenField){
11745 this.hiddenField.dom.value = this.value;
11749 clearItem : function()
11751 if(!this.multiple){
11757 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11764 inputEl: function ()
11767 return this.searchField;
11769 return this.el.select('input.form-control',true).first();
11773 onTickableFooterButtonClick : function(e, btn, el)
11775 e.preventDefault();
11777 if(btn && btn.name == 'cancel'){
11778 this.tickItems = Roo.apply([], this.item);
11787 Roo.each(this.tickItems, function(o){
11798 * @cfg {Boolean} grow
11802 * @cfg {Number} growMin
11806 * @cfg {Number} growMax
11816 * Ext JS Library 1.1.1
11817 * Copyright(c) 2006-2007, Ext JS, LLC.
11819 * Originally Released Under LGPL - original licence link has changed is not relivant.
11822 * <script type="text/javascript">
11827 * @extends Roo.util.Observable
11828 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11829 * This class also supports single and multi selection modes. <br>
11830 * Create a data model bound view:
11832 var store = new Roo.data.Store(...);
11834 var view = new Roo.View({
11836 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11838 singleSelect: true,
11839 selectedClass: "ydataview-selected",
11843 // listen for node click?
11844 view.on("click", function(vw, index, node, e){
11845 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11849 dataModel.load("foobar.xml");
11851 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11853 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11854 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11856 * Note: old style constructor is still suported (container, template, config)
11859 * Create a new View
11860 * @param {Object} config The config object
11863 Roo.View = function(config, depreciated_tpl, depreciated_config){
11865 this.parent = false;
11867 if (typeof(depreciated_tpl) == 'undefined') {
11868 // new way.. - universal constructor.
11869 Roo.apply(this, config);
11870 this.el = Roo.get(this.el);
11873 this.el = Roo.get(config);
11874 this.tpl = depreciated_tpl;
11875 Roo.apply(this, depreciated_config);
11877 this.wrapEl = this.el.wrap().wrap();
11878 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11881 if(typeof(this.tpl) == "string"){
11882 this.tpl = new Roo.Template(this.tpl);
11884 // support xtype ctors..
11885 this.tpl = new Roo.factory(this.tpl, Roo);
11889 this.tpl.compile();
11894 * @event beforeclick
11895 * Fires before a click is processed. Returns false to cancel the default action.
11896 * @param {Roo.View} this
11897 * @param {Number} index The index of the target node
11898 * @param {HTMLElement} node The target node
11899 * @param {Roo.EventObject} e The raw event object
11901 "beforeclick" : true,
11904 * Fires when a template node is clicked.
11905 * @param {Roo.View} this
11906 * @param {Number} index The index of the target node
11907 * @param {HTMLElement} node The target node
11908 * @param {Roo.EventObject} e The raw event object
11913 * Fires when a template node is double clicked.
11914 * @param {Roo.View} this
11915 * @param {Number} index The index of the target node
11916 * @param {HTMLElement} node The target node
11917 * @param {Roo.EventObject} e The raw event object
11921 * @event contextmenu
11922 * Fires when a template node is right clicked.
11923 * @param {Roo.View} this
11924 * @param {Number} index The index of the target node
11925 * @param {HTMLElement} node The target node
11926 * @param {Roo.EventObject} e The raw event object
11928 "contextmenu" : true,
11930 * @event selectionchange
11931 * Fires when the selected nodes change.
11932 * @param {Roo.View} this
11933 * @param {Array} selections Array of the selected nodes
11935 "selectionchange" : true,
11938 * @event beforeselect
11939 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11940 * @param {Roo.View} this
11941 * @param {HTMLElement} node The node to be selected
11942 * @param {Array} selections Array of currently selected nodes
11944 "beforeselect" : true,
11946 * @event preparedata
11947 * Fires on every row to render, to allow you to change the data.
11948 * @param {Roo.View} this
11949 * @param {Object} data to be rendered (change this)
11951 "preparedata" : true
11959 "click": this.onClick,
11960 "dblclick": this.onDblClick,
11961 "contextmenu": this.onContextMenu,
11965 this.selections = [];
11967 this.cmp = new Roo.CompositeElementLite([]);
11969 this.store = Roo.factory(this.store, Roo.data);
11970 this.setStore(this.store, true);
11973 if ( this.footer && this.footer.xtype) {
11975 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11977 this.footer.dataSource = this.store
11978 this.footer.container = fctr;
11979 this.footer = Roo.factory(this.footer, Roo);
11980 fctr.insertFirst(this.el);
11982 // this is a bit insane - as the paging toolbar seems to detach the el..
11983 // dom.parentNode.parentNode.parentNode
11984 // they get detached?
11988 Roo.View.superclass.constructor.call(this);
11993 Roo.extend(Roo.View, Roo.util.Observable, {
11996 * @cfg {Roo.data.Store} store Data store to load data from.
12001 * @cfg {String|Roo.Element} el The container element.
12006 * @cfg {String|Roo.Template} tpl The template used by this View
12010 * @cfg {String} dataName the named area of the template to use as the data area
12011 * Works with domtemplates roo-name="name"
12015 * @cfg {String} selectedClass The css class to add to selected nodes
12017 selectedClass : "x-view-selected",
12019 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12024 * @cfg {String} text to display on mask (default Loading)
12028 * @cfg {Boolean} multiSelect Allow multiple selection
12030 multiSelect : false,
12032 * @cfg {Boolean} singleSelect Allow single selection
12034 singleSelect: false,
12037 * @cfg {Boolean} toggleSelect - selecting
12039 toggleSelect : false,
12042 * @cfg {Boolean} tickable - selecting
12047 * Returns the element this view is bound to.
12048 * @return {Roo.Element}
12050 getEl : function(){
12051 return this.wrapEl;
12057 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12059 refresh : function(){
12060 Roo.log('refresh');
12063 // if we are using something like 'domtemplate', then
12064 // the what gets used is:
12065 // t.applySubtemplate(NAME, data, wrapping data..)
12066 // the outer template then get' applied with
12067 // the store 'extra data'
12068 // and the body get's added to the
12069 // roo-name="data" node?
12070 // <span class='roo-tpl-{name}'></span> ?????
12074 this.clearSelections();
12075 this.el.update("");
12077 var records = this.store.getRange();
12078 if(records.length < 1) {
12080 // is this valid?? = should it render a template??
12082 this.el.update(this.emptyText);
12086 if (this.dataName) {
12087 this.el.update(t.apply(this.store.meta)); //????
12088 el = this.el.child('.roo-tpl-' + this.dataName);
12091 for(var i = 0, len = records.length; i < len; i++){
12092 var data = this.prepareData(records[i].data, i, records[i]);
12093 this.fireEvent("preparedata", this, data, i, records[i]);
12095 var d = Roo.apply({}, data);
12098 Roo.apply(d, {'roo-id' : Roo.id()});
12102 Roo.each(this.parent.item, function(item){
12103 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12106 Roo.apply(d, {'roo-data-checked' : 'checked'});
12110 html[html.length] = Roo.util.Format.trim(
12112 t.applySubtemplate(this.dataName, d, this.store.meta) :
12119 el.update(html.join(""));
12120 this.nodes = el.dom.childNodes;
12121 this.updateIndexes(0);
12126 * Function to override to reformat the data that is sent to
12127 * the template for each node.
12128 * DEPRICATED - use the preparedata event handler.
12129 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12130 * a JSON object for an UpdateManager bound view).
12132 prepareData : function(data, index, record)
12134 this.fireEvent("preparedata", this, data, index, record);
12138 onUpdate : function(ds, record){
12139 Roo.log('on update');
12140 this.clearSelections();
12141 var index = this.store.indexOf(record);
12142 var n = this.nodes[index];
12143 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12144 n.parentNode.removeChild(n);
12145 this.updateIndexes(index, index);
12151 onAdd : function(ds, records, index)
12153 Roo.log(['on Add', ds, records, index] );
12154 this.clearSelections();
12155 if(this.nodes.length == 0){
12159 var n = this.nodes[index];
12160 for(var i = 0, len = records.length; i < len; i++){
12161 var d = this.prepareData(records[i].data, i, records[i]);
12163 this.tpl.insertBefore(n, d);
12166 this.tpl.append(this.el, d);
12169 this.updateIndexes(index);
12172 onRemove : function(ds, record, index){
12173 Roo.log('onRemove');
12174 this.clearSelections();
12175 var el = this.dataName ?
12176 this.el.child('.roo-tpl-' + this.dataName) :
12179 el.dom.removeChild(this.nodes[index]);
12180 this.updateIndexes(index);
12184 * Refresh an individual node.
12185 * @param {Number} index
12187 refreshNode : function(index){
12188 this.onUpdate(this.store, this.store.getAt(index));
12191 updateIndexes : function(startIndex, endIndex){
12192 var ns = this.nodes;
12193 startIndex = startIndex || 0;
12194 endIndex = endIndex || ns.length - 1;
12195 for(var i = startIndex; i <= endIndex; i++){
12196 ns[i].nodeIndex = i;
12201 * Changes the data store this view uses and refresh the view.
12202 * @param {Store} store
12204 setStore : function(store, initial){
12205 if(!initial && this.store){
12206 this.store.un("datachanged", this.refresh);
12207 this.store.un("add", this.onAdd);
12208 this.store.un("remove", this.onRemove);
12209 this.store.un("update", this.onUpdate);
12210 this.store.un("clear", this.refresh);
12211 this.store.un("beforeload", this.onBeforeLoad);
12212 this.store.un("load", this.onLoad);
12213 this.store.un("loadexception", this.onLoad);
12217 store.on("datachanged", this.refresh, this);
12218 store.on("add", this.onAdd, this);
12219 store.on("remove", this.onRemove, this);
12220 store.on("update", this.onUpdate, this);
12221 store.on("clear", this.refresh, this);
12222 store.on("beforeload", this.onBeforeLoad, this);
12223 store.on("load", this.onLoad, this);
12224 store.on("loadexception", this.onLoad, this);
12232 * onbeforeLoad - masks the loading area.
12235 onBeforeLoad : function(store,opts)
12237 Roo.log('onBeforeLoad');
12239 this.el.update("");
12241 this.el.mask(this.mask ? this.mask : "Loading" );
12243 onLoad : function ()
12250 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12251 * @param {HTMLElement} node
12252 * @return {HTMLElement} The template node
12254 findItemFromChild : function(node){
12255 var el = this.dataName ?
12256 this.el.child('.roo-tpl-' + this.dataName,true) :
12259 if(!node || node.parentNode == el){
12262 var p = node.parentNode;
12263 while(p && p != el){
12264 if(p.parentNode == el){
12273 onClick : function(e){
12274 var item = this.findItemFromChild(e.getTarget());
12276 var index = this.indexOf(item);
12277 if(this.onItemClick(item, index, e) !== false){
12278 this.fireEvent("click", this, index, item, e);
12281 this.clearSelections();
12286 onContextMenu : function(e){
12287 var item = this.findItemFromChild(e.getTarget());
12289 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12294 onDblClick : function(e){
12295 var item = this.findItemFromChild(e.getTarget());
12297 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12301 onItemClick : function(item, index, e)
12303 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12306 if (this.toggleSelect) {
12307 var m = this.isSelected(item) ? 'unselect' : 'select';
12310 _t[m](item, true, false);
12313 if(this.multiSelect || this.singleSelect){
12314 if(this.multiSelect && e.shiftKey && this.lastSelection){
12315 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12317 this.select(item, this.multiSelect && e.ctrlKey);
12318 this.lastSelection = item;
12321 if(!this.tickable){
12322 e.preventDefault();
12330 * Get the number of selected nodes.
12333 getSelectionCount : function(){
12334 return this.selections.length;
12338 * Get the currently selected nodes.
12339 * @return {Array} An array of HTMLElements
12341 getSelectedNodes : function(){
12342 return this.selections;
12346 * Get the indexes of the selected nodes.
12349 getSelectedIndexes : function(){
12350 var indexes = [], s = this.selections;
12351 for(var i = 0, len = s.length; i < len; i++){
12352 indexes.push(s[i].nodeIndex);
12358 * Clear all selections
12359 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12361 clearSelections : function(suppressEvent){
12362 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12363 this.cmp.elements = this.selections;
12364 this.cmp.removeClass(this.selectedClass);
12365 this.selections = [];
12366 if(!suppressEvent){
12367 this.fireEvent("selectionchange", this, this.selections);
12373 * Returns true if the passed node is selected
12374 * @param {HTMLElement/Number} node The node or node index
12375 * @return {Boolean}
12377 isSelected : function(node){
12378 var s = this.selections;
12382 node = this.getNode(node);
12383 return s.indexOf(node) !== -1;
12388 * @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
12389 * @param {Boolean} keepExisting (optional) true to keep existing selections
12390 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12392 select : function(nodeInfo, keepExisting, suppressEvent){
12393 if(nodeInfo instanceof Array){
12395 this.clearSelections(true);
12397 for(var i = 0, len = nodeInfo.length; i < len; i++){
12398 this.select(nodeInfo[i], true, true);
12402 var node = this.getNode(nodeInfo);
12403 if(!node || this.isSelected(node)){
12404 return; // already selected.
12407 this.clearSelections(true);
12409 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12410 Roo.fly(node).addClass(this.selectedClass);
12411 this.selections.push(node);
12412 if(!suppressEvent){
12413 this.fireEvent("selectionchange", this, this.selections);
12421 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
12422 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12423 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12425 unselect : function(nodeInfo, keepExisting, suppressEvent)
12427 if(nodeInfo instanceof Array){
12428 Roo.each(this.selections, function(s) {
12429 this.unselect(s, nodeInfo);
12433 var node = this.getNode(nodeInfo);
12434 if(!node || !this.isSelected(node)){
12435 Roo.log("not selected");
12436 return; // not selected.
12440 Roo.each(this.selections, function(s) {
12442 Roo.fly(node).removeClass(this.selectedClass);
12449 this.selections= ns;
12450 this.fireEvent("selectionchange", this, this.selections);
12454 * Gets a template node.
12455 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12456 * @return {HTMLElement} The node or null if it wasn't found
12458 getNode : function(nodeInfo){
12459 if(typeof nodeInfo == "string"){
12460 return document.getElementById(nodeInfo);
12461 }else if(typeof nodeInfo == "number"){
12462 return this.nodes[nodeInfo];
12468 * Gets a range template nodes.
12469 * @param {Number} startIndex
12470 * @param {Number} endIndex
12471 * @return {Array} An array of nodes
12473 getNodes : function(start, end){
12474 var ns = this.nodes;
12475 start = start || 0;
12476 end = typeof end == "undefined" ? ns.length - 1 : end;
12479 for(var i = start; i <= end; i++){
12483 for(var i = start; i >= end; i--){
12491 * Finds the index of the passed node
12492 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12493 * @return {Number} The index of the node or -1
12495 indexOf : function(node){
12496 node = this.getNode(node);
12497 if(typeof node.nodeIndex == "number"){
12498 return node.nodeIndex;
12500 var ns = this.nodes;
12501 for(var i = 0, len = ns.length; i < len; i++){
12512 * based on jquery fullcalendar
12516 Roo.bootstrap = Roo.bootstrap || {};
12518 * @class Roo.bootstrap.Calendar
12519 * @extends Roo.bootstrap.Component
12520 * Bootstrap Calendar class
12521 * @cfg {Boolean} loadMask (true|false) default false
12522 * @cfg {Object} header generate the user specific header of the calendar, default false
12525 * Create a new Container
12526 * @param {Object} config The config object
12531 Roo.bootstrap.Calendar = function(config){
12532 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12536 * Fires when a date is selected
12537 * @param {DatePicker} this
12538 * @param {Date} date The selected date
12542 * @event monthchange
12543 * Fires when the displayed month changes
12544 * @param {DatePicker} this
12545 * @param {Date} date The selected month
12547 'monthchange': true,
12549 * @event evententer
12550 * Fires when mouse over an event
12551 * @param {Calendar} this
12552 * @param {event} Event
12554 'evententer': true,
12556 * @event eventleave
12557 * Fires when the mouse leaves an
12558 * @param {Calendar} this
12561 'eventleave': true,
12563 * @event eventclick
12564 * Fires when the mouse click an
12565 * @param {Calendar} this
12574 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12577 * @cfg {Number} startDay
12578 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12586 getAutoCreate : function(){
12589 var fc_button = function(name, corner, style, content ) {
12590 return Roo.apply({},{
12592 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12594 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12597 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12608 style : 'width:100%',
12615 cls : 'fc-header-left',
12617 fc_button('prev', 'left', 'arrow', '‹' ),
12618 fc_button('next', 'right', 'arrow', '›' ),
12619 { tag: 'span', cls: 'fc-header-space' },
12620 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12628 cls : 'fc-header-center',
12632 cls: 'fc-header-title',
12635 html : 'month / year'
12643 cls : 'fc-header-right',
12645 /* fc_button('month', 'left', '', 'month' ),
12646 fc_button('week', '', '', 'week' ),
12647 fc_button('day', 'right', '', 'day' )
12659 header = this.header;
12662 var cal_heads = function() {
12664 // fixme - handle this.
12666 for (var i =0; i < Date.dayNames.length; i++) {
12667 var d = Date.dayNames[i];
12670 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12671 html : d.substring(0,3)
12675 ret[0].cls += ' fc-first';
12676 ret[6].cls += ' fc-last';
12679 var cal_cell = function(n) {
12682 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12687 cls: 'fc-day-number',
12691 cls: 'fc-day-content',
12695 style: 'position: relative;' // height: 17px;
12707 var cal_rows = function() {
12710 for (var r = 0; r < 6; r++) {
12717 for (var i =0; i < Date.dayNames.length; i++) {
12718 var d = Date.dayNames[i];
12719 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12722 row.cn[0].cls+=' fc-first';
12723 row.cn[0].cn[0].style = 'min-height:90px';
12724 row.cn[6].cls+=' fc-last';
12728 ret[0].cls += ' fc-first';
12729 ret[4].cls += ' fc-prev-last';
12730 ret[5].cls += ' fc-last';
12737 cls: 'fc-border-separate',
12738 style : 'width:100%',
12746 cls : 'fc-first fc-last',
12764 cls : 'fc-content',
12765 style : "position: relative;",
12768 cls : 'fc-view fc-view-month fc-grid',
12769 style : 'position: relative',
12770 unselectable : 'on',
12773 cls : 'fc-event-container',
12774 style : 'position:absolute;z-index:8;top:0;left:0;'
12792 initEvents : function()
12795 throw "can not find store for calendar";
12801 style: "text-align:center",
12805 style: "background-color:white;width:50%;margin:250 auto",
12809 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12820 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12822 var size = this.el.select('.fc-content', true).first().getSize();
12823 this.maskEl.setSize(size.width, size.height);
12824 this.maskEl.enableDisplayMode("block");
12825 if(!this.loadMask){
12826 this.maskEl.hide();
12829 this.store = Roo.factory(this.store, Roo.data);
12830 this.store.on('load', this.onLoad, this);
12831 this.store.on('beforeload', this.onBeforeLoad, this);
12835 this.cells = this.el.select('.fc-day',true);
12836 //Roo.log(this.cells);
12837 this.textNodes = this.el.query('.fc-day-number');
12838 this.cells.addClassOnOver('fc-state-hover');
12840 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12841 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12842 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12843 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12845 this.on('monthchange', this.onMonthChange, this);
12847 this.update(new Date().clearTime());
12850 resize : function() {
12851 var sz = this.el.getSize();
12853 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12854 this.el.select('.fc-day-content div',true).setHeight(34);
12859 showPrevMonth : function(e){
12860 this.update(this.activeDate.add("mo", -1));
12862 showToday : function(e){
12863 this.update(new Date().clearTime());
12866 showNextMonth : function(e){
12867 this.update(this.activeDate.add("mo", 1));
12871 showPrevYear : function(){
12872 this.update(this.activeDate.add("y", -1));
12876 showNextYear : function(){
12877 this.update(this.activeDate.add("y", 1));
12882 update : function(date)
12884 var vd = this.activeDate;
12885 this.activeDate = date;
12886 // if(vd && this.el){
12887 // var t = date.getTime();
12888 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12889 // Roo.log('using add remove');
12891 // this.fireEvent('monthchange', this, date);
12893 // this.cells.removeClass("fc-state-highlight");
12894 // this.cells.each(function(c){
12895 // if(c.dateValue == t){
12896 // c.addClass("fc-state-highlight");
12897 // setTimeout(function(){
12898 // try{c.dom.firstChild.focus();}catch(e){}
12908 var days = date.getDaysInMonth();
12910 var firstOfMonth = date.getFirstDateOfMonth();
12911 var startingPos = firstOfMonth.getDay()-this.startDay;
12913 if(startingPos < this.startDay){
12917 var pm = date.add(Date.MONTH, -1);
12918 var prevStart = pm.getDaysInMonth()-startingPos;
12920 this.cells = this.el.select('.fc-day',true);
12921 this.textNodes = this.el.query('.fc-day-number');
12922 this.cells.addClassOnOver('fc-state-hover');
12924 var cells = this.cells.elements;
12925 var textEls = this.textNodes;
12927 Roo.each(cells, function(cell){
12928 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12931 days += startingPos;
12933 // convert everything to numbers so it's fast
12934 var day = 86400000;
12935 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12938 //Roo.log(prevStart);
12940 var today = new Date().clearTime().getTime();
12941 var sel = date.clearTime().getTime();
12942 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12943 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12944 var ddMatch = this.disabledDatesRE;
12945 var ddText = this.disabledDatesText;
12946 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12947 var ddaysText = this.disabledDaysText;
12948 var format = this.format;
12950 var setCellClass = function(cal, cell){
12954 //Roo.log('set Cell Class');
12956 var t = d.getTime();
12960 cell.dateValue = t;
12962 cell.className += " fc-today";
12963 cell.className += " fc-state-highlight";
12964 cell.title = cal.todayText;
12967 // disable highlight in other month..
12968 //cell.className += " fc-state-highlight";
12973 cell.className = " fc-state-disabled";
12974 cell.title = cal.minText;
12978 cell.className = " fc-state-disabled";
12979 cell.title = cal.maxText;
12983 if(ddays.indexOf(d.getDay()) != -1){
12984 cell.title = ddaysText;
12985 cell.className = " fc-state-disabled";
12988 if(ddMatch && format){
12989 var fvalue = d.dateFormat(format);
12990 if(ddMatch.test(fvalue)){
12991 cell.title = ddText.replace("%0", fvalue);
12992 cell.className = " fc-state-disabled";
12996 if (!cell.initialClassName) {
12997 cell.initialClassName = cell.dom.className;
13000 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13005 for(; i < startingPos; i++) {
13006 textEls[i].innerHTML = (++prevStart);
13007 d.setDate(d.getDate()+1);
13009 cells[i].className = "fc-past fc-other-month";
13010 setCellClass(this, cells[i]);
13015 for(; i < days; i++){
13016 intDay = i - startingPos + 1;
13017 textEls[i].innerHTML = (intDay);
13018 d.setDate(d.getDate()+1);
13020 cells[i].className = ''; // "x-date-active";
13021 setCellClass(this, cells[i]);
13025 for(; i < 42; i++) {
13026 textEls[i].innerHTML = (++extraDays);
13027 d.setDate(d.getDate()+1);
13029 cells[i].className = "fc-future fc-other-month";
13030 setCellClass(this, cells[i]);
13033 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13035 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13037 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13038 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13040 if(totalRows != 6){
13041 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13042 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13045 this.fireEvent('monthchange', this, date);
13049 if(!this.internalRender){
13050 var main = this.el.dom.firstChild;
13051 var w = main.offsetWidth;
13052 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13053 Roo.fly(main).setWidth(w);
13054 this.internalRender = true;
13055 // opera does not respect the auto grow header center column
13056 // then, after it gets a width opera refuses to recalculate
13057 // without a second pass
13058 if(Roo.isOpera && !this.secondPass){
13059 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13060 this.secondPass = true;
13061 this.update.defer(10, this, [date]);
13068 findCell : function(dt) {
13069 dt = dt.clearTime().getTime();
13071 this.cells.each(function(c){
13072 //Roo.log("check " +c.dateValue + '?=' + dt);
13073 if(c.dateValue == dt){
13083 findCells : function(ev) {
13084 var s = ev.start.clone().clearTime().getTime();
13086 var e= ev.end.clone().clearTime().getTime();
13089 this.cells.each(function(c){
13090 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13092 if(c.dateValue > e){
13095 if(c.dateValue < s){
13104 // findBestRow: function(cells)
13108 // for (var i =0 ; i < cells.length;i++) {
13109 // ret = Math.max(cells[i].rows || 0,ret);
13116 addItem : function(ev)
13118 // look for vertical location slot in
13119 var cells = this.findCells(ev);
13121 // ev.row = this.findBestRow(cells);
13123 // work out the location.
13127 for(var i =0; i < cells.length; i++) {
13129 cells[i].row = cells[0].row;
13132 cells[i].row = cells[i].row + 1;
13142 if (crow.start.getY() == cells[i].getY()) {
13144 crow.end = cells[i];
13161 cells[0].events.push(ev);
13163 this.calevents.push(ev);
13166 clearEvents: function() {
13168 if(!this.calevents){
13172 Roo.each(this.cells.elements, function(c){
13178 Roo.each(this.calevents, function(e) {
13179 Roo.each(e.els, function(el) {
13180 el.un('mouseenter' ,this.onEventEnter, this);
13181 el.un('mouseleave' ,this.onEventLeave, this);
13186 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13192 renderEvents: function()
13196 this.cells.each(function(c) {
13205 if(c.row != c.events.length){
13206 r = 4 - (4 - (c.row - c.events.length));
13209 c.events = ev.slice(0, r);
13210 c.more = ev.slice(r);
13212 if(c.more.length && c.more.length == 1){
13213 c.events.push(c.more.pop());
13216 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13220 this.cells.each(function(c) {
13222 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13225 for (var e = 0; e < c.events.length; e++){
13226 var ev = c.events[e];
13227 var rows = ev.rows;
13229 for(var i = 0; i < rows.length; i++) {
13231 // how many rows should it span..
13234 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13235 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13237 unselectable : "on",
13240 cls: 'fc-event-inner',
13244 // cls: 'fc-event-time',
13245 // html : cells.length > 1 ? '' : ev.time
13249 cls: 'fc-event-title',
13250 html : String.format('{0}', ev.title)
13257 cls: 'ui-resizable-handle ui-resizable-e',
13258 html : '  '
13265 cfg.cls += ' fc-event-start';
13267 if ((i+1) == rows.length) {
13268 cfg.cls += ' fc-event-end';
13271 var ctr = _this.el.select('.fc-event-container',true).first();
13272 var cg = ctr.createChild(cfg);
13274 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13275 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13277 var r = (c.more.length) ? 1 : 0;
13278 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13279 cg.setWidth(ebox.right - sbox.x -2);
13281 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13282 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13283 cg.on('click', _this.onEventClick, _this, ev);
13294 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13295 style : 'position: absolute',
13296 unselectable : "on",
13299 cls: 'fc-event-inner',
13303 cls: 'fc-event-title',
13311 cls: 'ui-resizable-handle ui-resizable-e',
13312 html : '  '
13318 var ctr = _this.el.select('.fc-event-container',true).first();
13319 var cg = ctr.createChild(cfg);
13321 var sbox = c.select('.fc-day-content',true).first().getBox();
13322 var ebox = c.select('.fc-day-content',true).first().getBox();
13324 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13325 cg.setWidth(ebox.right - sbox.x -2);
13327 cg.on('click', _this.onMoreEventClick, _this, c.more);
13337 onEventEnter: function (e, el,event,d) {
13338 this.fireEvent('evententer', this, el, event);
13341 onEventLeave: function (e, el,event,d) {
13342 this.fireEvent('eventleave', this, el, event);
13345 onEventClick: function (e, el,event,d) {
13346 this.fireEvent('eventclick', this, el, event);
13349 onMonthChange: function () {
13353 onMoreEventClick: function(e, el, more)
13357 this.calpopover.placement = 'right';
13358 this.calpopover.setTitle('More');
13360 this.calpopover.setContent('');
13362 var ctr = this.calpopover.el.select('.popover-content', true).first();
13364 Roo.each(more, function(m){
13366 cls : 'fc-event-hori fc-event-draggable',
13369 var cg = ctr.createChild(cfg);
13371 cg.on('click', _this.onEventClick, _this, m);
13374 this.calpopover.show(el);
13379 onLoad: function ()
13381 this.calevents = [];
13384 if(this.store.getCount() > 0){
13385 this.store.data.each(function(d){
13388 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13389 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13390 time : d.data.start_time,
13391 title : d.data.title,
13392 description : d.data.description,
13393 venue : d.data.venue
13398 this.renderEvents();
13400 if(this.calevents.length && this.loadMask){
13401 this.maskEl.hide();
13405 onBeforeLoad: function()
13407 this.clearEvents();
13409 this.maskEl.show();
13423 * @class Roo.bootstrap.Popover
13424 * @extends Roo.bootstrap.Component
13425 * Bootstrap Popover class
13426 * @cfg {String} html contents of the popover (or false to use children..)
13427 * @cfg {String} title of popover (or false to hide)
13428 * @cfg {String} placement how it is placed
13429 * @cfg {String} trigger click || hover (or false to trigger manually)
13430 * @cfg {String} over what (parent or false to trigger manually.)
13433 * Create a new Popover
13434 * @param {Object} config The config object
13437 Roo.bootstrap.Popover = function(config){
13438 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13441 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13443 title: 'Fill in a title',
13446 placement : 'right',
13447 trigger : 'hover', // hover
13451 can_build_overlaid : false,
13453 getChildContainer : function()
13455 return this.el.select('.popover-content',true).first();
13458 getAutoCreate : function(){
13459 Roo.log('make popover?');
13461 cls : 'popover roo-dynamic',
13462 style: 'display:block',
13468 cls : 'popover-inner',
13472 cls: 'popover-title',
13476 cls : 'popover-content',
13487 setTitle: function(str)
13489 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13491 setContent: function(str)
13493 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13495 // as it get's added to the bottom of the page.
13496 onRender : function(ct, position)
13498 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13500 var cfg = Roo.apply({}, this.getAutoCreate());
13504 cfg.cls += ' ' + this.cls;
13507 cfg.style = this.style;
13509 Roo.log("adding to ")
13510 this.el = Roo.get(document.body).createChild(cfg, position);
13516 initEvents : function()
13518 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13519 this.el.enableDisplayMode('block');
13521 if (this.over === false) {
13524 if (this.triggers === false) {
13527 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13528 var triggers = this.trigger ? this.trigger.split(' ') : [];
13529 Roo.each(triggers, function(trigger) {
13531 if (trigger == 'click') {
13532 on_el.on('click', this.toggle, this);
13533 } else if (trigger != 'manual') {
13534 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13535 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13537 on_el.on(eventIn ,this.enter, this);
13538 on_el.on(eventOut, this.leave, this);
13549 toggle : function () {
13550 this.hoverState == 'in' ? this.leave() : this.enter();
13553 enter : function () {
13556 clearTimeout(this.timeout);
13558 this.hoverState = 'in'
13560 if (!this.delay || !this.delay.show) {
13565 this.timeout = setTimeout(function () {
13566 if (_t.hoverState == 'in') {
13569 }, this.delay.show)
13571 leave : function() {
13572 clearTimeout(this.timeout);
13574 this.hoverState = 'out'
13576 if (!this.delay || !this.delay.hide) {
13581 this.timeout = setTimeout(function () {
13582 if (_t.hoverState == 'out') {
13585 }, this.delay.hide)
13588 show : function (on_el)
13591 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13594 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13595 if (this.html !== false) {
13596 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13598 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13599 if (!this.title.length) {
13600 this.el.select('.popover-title',true).hide();
13603 var placement = typeof this.placement == 'function' ?
13604 this.placement.call(this, this.el, on_el) :
13607 var autoToken = /\s?auto?\s?/i;
13608 var autoPlace = autoToken.test(placement);
13610 placement = placement.replace(autoToken, '') || 'top';
13614 //this.el.setXY([0,0]);
13616 this.el.dom.style.display='block';
13617 this.el.addClass(placement);
13619 //this.el.appendTo(on_el);
13621 var p = this.getPosition();
13622 var box = this.el.getBox();
13627 var align = Roo.bootstrap.Popover.alignment[placement]
13628 this.el.alignTo(on_el, align[0],align[1]);
13629 //var arrow = this.el.select('.arrow',true).first();
13630 //arrow.set(align[2],
13632 this.el.addClass('in');
13633 this.hoverState = null;
13635 if (this.el.hasClass('fade')) {
13642 this.el.setXY([0,0]);
13643 this.el.removeClass('in');
13650 Roo.bootstrap.Popover.alignment = {
13651 'left' : ['r-l', [-10,0], 'right'],
13652 'right' : ['l-r', [10,0], 'left'],
13653 'bottom' : ['t-b', [0,10], 'top'],
13654 'top' : [ 'b-t', [0,-10], 'bottom']
13665 * @class Roo.bootstrap.Progress
13666 * @extends Roo.bootstrap.Component
13667 * Bootstrap Progress class
13668 * @cfg {Boolean} striped striped of the progress bar
13669 * @cfg {Boolean} active animated of the progress bar
13673 * Create a new Progress
13674 * @param {Object} config The config object
13677 Roo.bootstrap.Progress = function(config){
13678 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13681 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13686 getAutoCreate : function(){
13694 cfg.cls += ' progress-striped';
13698 cfg.cls += ' active';
13717 * @class Roo.bootstrap.ProgressBar
13718 * @extends Roo.bootstrap.Component
13719 * Bootstrap ProgressBar class
13720 * @cfg {Number} aria_valuenow aria-value now
13721 * @cfg {Number} aria_valuemin aria-value min
13722 * @cfg {Number} aria_valuemax aria-value max
13723 * @cfg {String} label label for the progress bar
13724 * @cfg {String} panel (success | info | warning | danger )
13725 * @cfg {String} role role of the progress bar
13726 * @cfg {String} sr_only text
13730 * Create a new ProgressBar
13731 * @param {Object} config The config object
13734 Roo.bootstrap.ProgressBar = function(config){
13735 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13738 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13742 aria_valuemax : 100,
13748 getAutoCreate : function()
13753 cls: 'progress-bar',
13754 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13766 cfg.role = this.role;
13769 if(this.aria_valuenow){
13770 cfg['aria-valuenow'] = this.aria_valuenow;
13773 if(this.aria_valuemin){
13774 cfg['aria-valuemin'] = this.aria_valuemin;
13777 if(this.aria_valuemax){
13778 cfg['aria-valuemax'] = this.aria_valuemax;
13781 if(this.label && !this.sr_only){
13782 cfg.html = this.label;
13786 cfg.cls += ' progress-bar-' + this.panel;
13792 update : function(aria_valuenow)
13794 this.aria_valuenow = aria_valuenow;
13796 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13811 * @class Roo.bootstrap.TabGroup
13812 * @extends Roo.bootstrap.Column
13813 * Bootstrap Column class
13814 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13815 * @cfg {Boolean} carousel true to make the group behave like a carousel
13818 * Create a new TabGroup
13819 * @param {Object} config The config object
13822 Roo.bootstrap.TabGroup = function(config){
13823 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13825 this.navId = Roo.id();
13828 Roo.bootstrap.TabGroup.register(this);
13832 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13835 transition : false,
13837 getAutoCreate : function()
13839 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13841 cfg.cls += ' tab-content';
13843 if (this.carousel) {
13844 cfg.cls += ' carousel slide';
13846 cls : 'carousel-inner'
13853 getChildContainer : function()
13855 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13859 * register a Navigation item
13860 * @param {Roo.bootstrap.NavItem} the navitem to add
13862 register : function(item)
13864 this.tabs.push( item);
13865 item.navId = this.navId; // not really needed..
13869 getActivePanel : function()
13872 Roo.each(this.tabs, function(t) {
13882 getPanelByName : function(n)
13885 Roo.each(this.tabs, function(t) {
13886 if (t.tabId == n) {
13894 indexOfPanel : function(p)
13897 Roo.each(this.tabs, function(t,i) {
13898 if (t.tabId == p.tabId) {
13907 * show a specific panel
13908 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13909 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13911 showPanel : function (pan)
13914 if (typeof(pan) == 'number') {
13915 pan = this.tabs[pan];
13917 if (typeof(pan) == 'string') {
13918 pan = this.getPanelByName(pan);
13920 if (pan.tabId == this.getActivePanel().tabId) {
13923 var cur = this.getActivePanel();
13925 if (false === cur.fireEvent('beforedeactivate')) {
13929 if (this.carousel) {
13930 this.transition = true;
13931 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13932 var lr = dir == 'next' ? 'left' : 'right';
13933 pan.el.addClass(dir); // or prev
13934 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13935 cur.el.addClass(lr); // or right
13936 pan.el.addClass(lr);
13939 cur.el.on('transitionend', function() {
13940 Roo.log("trans end?");
13942 pan.el.removeClass([lr,dir]);
13943 pan.setActive(true);
13945 cur.el.removeClass([lr]);
13946 cur.setActive(false);
13948 _this.transition = false;
13950 }, this, { single: true } );
13954 cur.setActive(false);
13955 pan.setActive(true);
13959 showPanelNext : function()
13961 var i = this.indexOfPanel(this.getActivePanel());
13962 if (i > this.tabs.length) {
13965 this.showPanel(this.tabs[i+1]);
13967 showPanelPrev : function()
13969 var i = this.indexOfPanel(this.getActivePanel());
13973 this.showPanel(this.tabs[i-1]);
13984 Roo.apply(Roo.bootstrap.TabGroup, {
13988 * register a Navigation Group
13989 * @param {Roo.bootstrap.NavGroup} the navgroup to add
13991 register : function(navgrp)
13993 this.groups[navgrp.navId] = navgrp;
13997 * fetch a Navigation Group based on the navigation ID
13998 * if one does not exist , it will get created.
13999 * @param {string} the navgroup to add
14000 * @returns {Roo.bootstrap.NavGroup} the navgroup
14002 get: function(navId) {
14003 if (typeof(this.groups[navId]) == 'undefined') {
14004 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14006 return this.groups[navId] ;
14021 * @class Roo.bootstrap.TabPanel
14022 * @extends Roo.bootstrap.Component
14023 * Bootstrap TabPanel class
14024 * @cfg {Boolean} active panel active
14025 * @cfg {String} html panel content
14026 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14027 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14031 * Create a new TabPanel
14032 * @param {Object} config The config object
14035 Roo.bootstrap.TabPanel = function(config){
14036 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14040 * Fires when the active status changes
14041 * @param {Roo.bootstrap.TabPanel} this
14042 * @param {Boolean} state the new state
14047 * @event beforedeactivate
14048 * Fires before a tab is de-activated - can be used to do validation on a form.
14049 * @param {Roo.bootstrap.TabPanel} this
14050 * @return {Boolean} false if there is an error
14053 'beforedeactivate': true
14056 this.tabId = this.tabId || Roo.id();
14060 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14067 getAutoCreate : function(){
14070 // item is needed for carousel - not sure if it has any effect otherwise
14071 cls: 'tab-pane item',
14072 html: this.html || ''
14076 cfg.cls += ' active';
14080 cfg.tabId = this.tabId;
14087 initEvents: function()
14089 Roo.log('-------- init events on tab panel ---------');
14091 var p = this.parent();
14092 this.navId = this.navId || p.navId;
14094 if (typeof(this.navId) != 'undefined') {
14095 // not really needed.. but just in case.. parent should be a NavGroup.
14096 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14097 Roo.log(['register', tg, this]);
14103 onRender : function(ct, position)
14105 // Roo.log("Call onRender: " + this.xtype);
14107 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14115 setActive: function(state)
14117 Roo.log("panel - set active " + this.tabId + "=" + state);
14119 this.active = state;
14121 this.el.removeClass('active');
14123 } else if (!this.el.hasClass('active')) {
14124 this.el.addClass('active');
14126 this.fireEvent('changed', this, state);
14143 * @class Roo.bootstrap.DateField
14144 * @extends Roo.bootstrap.Input
14145 * Bootstrap DateField class
14146 * @cfg {Number} weekStart default 0
14147 * @cfg {Number} weekStart default 0
14148 * @cfg {Number} viewMode default empty, (months|years)
14149 * @cfg {Number} minViewMode default empty, (months|years)
14150 * @cfg {Number} startDate default -Infinity
14151 * @cfg {Number} endDate default Infinity
14152 * @cfg {Boolean} todayHighlight default false
14153 * @cfg {Boolean} todayBtn default false
14154 * @cfg {Boolean} calendarWeeks default false
14155 * @cfg {Object} daysOfWeekDisabled default empty
14157 * @cfg {Boolean} keyboardNavigation default true
14158 * @cfg {String} language default en
14161 * Create a new DateField
14162 * @param {Object} config The config object
14165 Roo.bootstrap.DateField = function(config){
14166 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14170 * Fires when this field show.
14171 * @param {Roo.bootstrap.DateField} this
14172 * @param {Mixed} date The date value
14177 * Fires when this field hide.
14178 * @param {Roo.bootstrap.DateField} this
14179 * @param {Mixed} date The date value
14184 * Fires when select a date.
14185 * @param {Roo.bootstrap.DateField} this
14186 * @param {Mixed} date The date value
14192 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14195 * @cfg {String} format
14196 * The default date format string which can be overriden for localization support. The format must be
14197 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14201 * @cfg {String} altFormats
14202 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14203 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14205 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14213 todayHighlight : false,
14219 keyboardNavigation: true,
14221 calendarWeeks: false,
14223 startDate: -Infinity,
14227 daysOfWeekDisabled: [],
14231 UTCDate: function()
14233 return new Date(Date.UTC.apply(Date, arguments));
14236 UTCToday: function()
14238 var today = new Date();
14239 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14242 getDate: function() {
14243 var d = this.getUTCDate();
14244 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14247 getUTCDate: function() {
14251 setDate: function(d) {
14252 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14255 setUTCDate: function(d) {
14257 this.setValue(this.formatDate(this.date));
14260 onRender: function(ct, position)
14263 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14265 this.language = this.language || 'en';
14266 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14267 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14269 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14270 this.format = this.format || 'm/d/y';
14271 this.isInline = false;
14272 this.isInput = true;
14273 this.component = this.el.select('.add-on', true).first() || false;
14274 this.component = (this.component && this.component.length === 0) ? false : this.component;
14275 this.hasInput = this.component && this.inputEL().length;
14277 if (typeof(this.minViewMode === 'string')) {
14278 switch (this.minViewMode) {
14280 this.minViewMode = 1;
14283 this.minViewMode = 2;
14286 this.minViewMode = 0;
14291 if (typeof(this.viewMode === 'string')) {
14292 switch (this.viewMode) {
14305 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14307 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14309 this.picker().on('mousedown', this.onMousedown, this);
14310 this.picker().on('click', this.onClick, this);
14312 this.picker().addClass('datepicker-dropdown');
14314 this.startViewMode = this.viewMode;
14317 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14318 if(!this.calendarWeeks){
14323 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14324 v.attr('colspan', function(i, val){
14325 return parseInt(val) + 1;
14330 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14332 this.setStartDate(this.startDate);
14333 this.setEndDate(this.endDate);
14335 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14342 if(this.isInline) {
14347 picker : function()
14349 return this.el.select('.datepicker', true).first();
14352 fillDow: function()
14354 var dowCnt = this.weekStart;
14363 if(this.calendarWeeks){
14371 while (dowCnt < this.weekStart + 7) {
14375 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14379 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14382 fillMonths: function()
14385 var months = this.picker().select('>.datepicker-months td', true).first();
14387 months.dom.innerHTML = '';
14393 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14396 months.createChild(month);
14404 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14406 if (this.date < this.startDate) {
14407 this.viewDate = new Date(this.startDate);
14408 } else if (this.date > this.endDate) {
14409 this.viewDate = new Date(this.endDate);
14411 this.viewDate = new Date(this.date);
14419 var d = new Date(this.viewDate),
14420 year = d.getUTCFullYear(),
14421 month = d.getUTCMonth(),
14422 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14423 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14424 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14425 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14426 currentDate = this.date && this.date.valueOf(),
14427 today = this.UTCToday();
14429 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14431 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14433 // this.picker.select('>tfoot th.today').
14434 // .text(dates[this.language].today)
14435 // .toggle(this.todayBtn !== false);
14437 this.updateNavArrows();
14440 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14442 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14444 prevMonth.setUTCDate(day);
14446 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14448 var nextMonth = new Date(prevMonth);
14450 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14452 nextMonth = nextMonth.valueOf();
14454 var fillMonths = false;
14456 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14458 while(prevMonth.valueOf() < nextMonth) {
14461 if (prevMonth.getUTCDay() === this.weekStart) {
14463 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14471 if(this.calendarWeeks){
14472 // ISO 8601: First week contains first thursday.
14473 // ISO also states week starts on Monday, but we can be more abstract here.
14475 // Start of current week: based on weekstart/current date
14476 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14477 // Thursday of this week
14478 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14479 // First Thursday of year, year from thursday
14480 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14481 // Calendar week: ms between thursdays, div ms per day, div 7 days
14482 calWeek = (th - yth) / 864e5 / 7 + 1;
14484 fillMonths.cn.push({
14492 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14494 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14497 if (this.todayHighlight &&
14498 prevMonth.getUTCFullYear() == today.getFullYear() &&
14499 prevMonth.getUTCMonth() == today.getMonth() &&
14500 prevMonth.getUTCDate() == today.getDate()) {
14501 clsName += ' today';
14504 if (currentDate && prevMonth.valueOf() === currentDate) {
14505 clsName += ' active';
14508 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14509 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14510 clsName += ' disabled';
14513 fillMonths.cn.push({
14515 cls: 'day ' + clsName,
14516 html: prevMonth.getDate()
14519 prevMonth.setDate(prevMonth.getDate()+1);
14522 var currentYear = this.date && this.date.getUTCFullYear();
14523 var currentMonth = this.date && this.date.getUTCMonth();
14525 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14527 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14528 v.removeClass('active');
14530 if(currentYear === year && k === currentMonth){
14531 v.addClass('active');
14534 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14535 v.addClass('disabled');
14541 year = parseInt(year/10, 10) * 10;
14543 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14545 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14548 for (var i = -1; i < 11; i++) {
14549 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14551 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14559 showMode: function(dir)
14562 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14564 Roo.each(this.picker().select('>div',true).elements, function(v){
14565 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14568 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14573 if(this.isInline) return;
14575 this.picker().removeClass(['bottom', 'top']);
14577 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14579 * place to the top of element!
14583 this.picker().addClass('top');
14584 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14589 this.picker().addClass('bottom');
14591 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14594 parseDate : function(value)
14596 if(!value || value instanceof Date){
14599 var v = Date.parseDate(value, this.format);
14600 if (!v && this.useIso) {
14601 v = Date.parseDate(value, 'Y-m-d');
14603 if(!v && this.altFormats){
14604 if(!this.altFormatsArray){
14605 this.altFormatsArray = this.altFormats.split("|");
14607 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14608 v = Date.parseDate(value, this.altFormatsArray[i]);
14614 formatDate : function(date, fmt)
14616 return (!date || !(date instanceof Date)) ?
14617 date : date.dateFormat(fmt || this.format);
14620 onFocus : function()
14622 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14626 onBlur : function()
14628 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14630 var d = this.inputEl().getValue();
14641 this.picker().show();
14645 this.fireEvent('show', this, this.date);
14650 if(this.isInline) return;
14651 this.picker().hide();
14652 this.viewMode = this.startViewMode;
14655 this.fireEvent('hide', this, this.date);
14659 onMousedown: function(e)
14661 e.stopPropagation();
14662 e.preventDefault();
14667 Roo.bootstrap.DateField.superclass.keyup.call(this);
14671 setValue: function(v)
14673 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14675 var d = new Date(v);
14677 if(isNaN(d.getTime())){
14681 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14685 this.fireEvent('select', this, this.date);
14689 getValue: function()
14691 return this.formatDate(this.date);
14694 fireKey: function(e)
14696 if (!this.picker().isVisible()){
14697 if (e.keyCode == 27) // allow escape to hide and re-show picker
14702 var dateChanged = false,
14704 newDate, newViewDate;
14709 e.preventDefault();
14713 if (!this.keyboardNavigation) break;
14714 dir = e.keyCode == 37 ? -1 : 1;
14717 newDate = this.moveYear(this.date, dir);
14718 newViewDate = this.moveYear(this.viewDate, dir);
14719 } else if (e.shiftKey){
14720 newDate = this.moveMonth(this.date, dir);
14721 newViewDate = this.moveMonth(this.viewDate, dir);
14723 newDate = new Date(this.date);
14724 newDate.setUTCDate(this.date.getUTCDate() + dir);
14725 newViewDate = new Date(this.viewDate);
14726 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14728 if (this.dateWithinRange(newDate)){
14729 this.date = newDate;
14730 this.viewDate = newViewDate;
14731 this.setValue(this.formatDate(this.date));
14733 e.preventDefault();
14734 dateChanged = true;
14739 if (!this.keyboardNavigation) break;
14740 dir = e.keyCode == 38 ? -1 : 1;
14742 newDate = this.moveYear(this.date, dir);
14743 newViewDate = this.moveYear(this.viewDate, dir);
14744 } else if (e.shiftKey){
14745 newDate = this.moveMonth(this.date, dir);
14746 newViewDate = this.moveMonth(this.viewDate, dir);
14748 newDate = new Date(this.date);
14749 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14750 newViewDate = new Date(this.viewDate);
14751 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14753 if (this.dateWithinRange(newDate)){
14754 this.date = newDate;
14755 this.viewDate = newViewDate;
14756 this.setValue(this.formatDate(this.date));
14758 e.preventDefault();
14759 dateChanged = true;
14763 this.setValue(this.formatDate(this.date));
14765 e.preventDefault();
14768 this.setValue(this.formatDate(this.date));
14782 onClick: function(e)
14784 e.stopPropagation();
14785 e.preventDefault();
14787 var target = e.getTarget();
14789 if(target.nodeName.toLowerCase() === 'i'){
14790 target = Roo.get(target).dom.parentNode;
14793 var nodeName = target.nodeName;
14794 var className = target.className;
14795 var html = target.innerHTML;
14797 switch(nodeName.toLowerCase()) {
14799 switch(className) {
14805 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14806 switch(this.viewMode){
14808 this.viewDate = this.moveMonth(this.viewDate, dir);
14812 this.viewDate = this.moveYear(this.viewDate, dir);
14818 var date = new Date();
14819 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14821 this.setValue(this.formatDate(this.date));
14828 if (className.indexOf('disabled') === -1) {
14829 this.viewDate.setUTCDate(1);
14830 if (className.indexOf('month') !== -1) {
14831 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14833 var year = parseInt(html, 10) || 0;
14834 this.viewDate.setUTCFullYear(year);
14843 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14844 var day = parseInt(html, 10) || 1;
14845 var year = this.viewDate.getUTCFullYear(),
14846 month = this.viewDate.getUTCMonth();
14848 if (className.indexOf('old') !== -1) {
14855 } else if (className.indexOf('new') !== -1) {
14863 this.date = this.UTCDate(year, month, day,0,0,0,0);
14864 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14866 this.setValue(this.formatDate(this.date));
14873 setStartDate: function(startDate)
14875 this.startDate = startDate || -Infinity;
14876 if (this.startDate !== -Infinity) {
14877 this.startDate = this.parseDate(this.startDate);
14880 this.updateNavArrows();
14883 setEndDate: function(endDate)
14885 this.endDate = endDate || Infinity;
14886 if (this.endDate !== Infinity) {
14887 this.endDate = this.parseDate(this.endDate);
14890 this.updateNavArrows();
14893 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14895 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14896 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14897 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14899 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14900 return parseInt(d, 10);
14903 this.updateNavArrows();
14906 updateNavArrows: function()
14908 var d = new Date(this.viewDate),
14909 year = d.getUTCFullYear(),
14910 month = d.getUTCMonth();
14912 Roo.each(this.picker().select('.prev', true).elements, function(v){
14914 switch (this.viewMode) {
14917 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14923 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14930 Roo.each(this.picker().select('.next', true).elements, function(v){
14932 switch (this.viewMode) {
14935 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14941 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14949 moveMonth: function(date, dir)
14951 if (!dir) return date;
14952 var new_date = new Date(date.valueOf()),
14953 day = new_date.getUTCDate(),
14954 month = new_date.getUTCMonth(),
14955 mag = Math.abs(dir),
14957 dir = dir > 0 ? 1 : -1;
14960 // If going back one month, make sure month is not current month
14961 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14963 return new_date.getUTCMonth() == month;
14965 // If going forward one month, make sure month is as expected
14966 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14968 return new_date.getUTCMonth() != new_month;
14970 new_month = month + dir;
14971 new_date.setUTCMonth(new_month);
14972 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14973 if (new_month < 0 || new_month > 11)
14974 new_month = (new_month + 12) % 12;
14976 // For magnitudes >1, move one month at a time...
14977 for (var i=0; i<mag; i++)
14978 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14979 new_date = this.moveMonth(new_date, dir);
14980 // ...then reset the day, keeping it in the new month
14981 new_month = new_date.getUTCMonth();
14982 new_date.setUTCDate(day);
14984 return new_month != new_date.getUTCMonth();
14987 // Common date-resetting loop -- if date is beyond end of month, make it
14990 new_date.setUTCDate(--day);
14991 new_date.setUTCMonth(new_month);
14996 moveYear: function(date, dir)
14998 return this.moveMonth(date, dir*12);
15001 dateWithinRange: function(date)
15003 return date >= this.startDate && date <= this.endDate;
15009 this.picker().remove();
15014 Roo.apply(Roo.bootstrap.DateField, {
15025 html: '<i class="fa fa-arrow-left"/>'
15035 html: '<i class="fa fa-arrow-right"/>'
15077 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15078 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15079 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15080 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15081 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15094 navFnc: 'FullYear',
15099 navFnc: 'FullYear',
15104 Roo.apply(Roo.bootstrap.DateField, {
15108 cls: 'datepicker dropdown-menu',
15112 cls: 'datepicker-days',
15116 cls: 'table-condensed',
15118 Roo.bootstrap.DateField.head,
15122 Roo.bootstrap.DateField.footer
15129 cls: 'datepicker-months',
15133 cls: 'table-condensed',
15135 Roo.bootstrap.DateField.head,
15136 Roo.bootstrap.DateField.content,
15137 Roo.bootstrap.DateField.footer
15144 cls: 'datepicker-years',
15148 cls: 'table-condensed',
15150 Roo.bootstrap.DateField.head,
15151 Roo.bootstrap.DateField.content,
15152 Roo.bootstrap.DateField.footer
15171 * @class Roo.bootstrap.TimeField
15172 * @extends Roo.bootstrap.Input
15173 * Bootstrap DateField class
15177 * Create a new TimeField
15178 * @param {Object} config The config object
15181 Roo.bootstrap.TimeField = function(config){
15182 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15186 * Fires when this field show.
15187 * @param {Roo.bootstrap.DateField} this
15188 * @param {Mixed} date The date value
15193 * Fires when this field hide.
15194 * @param {Roo.bootstrap.DateField} this
15195 * @param {Mixed} date The date value
15200 * Fires when select a date.
15201 * @param {Roo.bootstrap.DateField} this
15202 * @param {Mixed} date The date value
15208 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15211 * @cfg {String} format
15212 * The default time format string which can be overriden for localization support. The format must be
15213 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15217 onRender: function(ct, position)
15220 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15222 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15224 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15226 this.pop = this.picker().select('>.datepicker-time',true).first();
15227 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15229 this.picker().on('mousedown', this.onMousedown, this);
15230 this.picker().on('click', this.onClick, this);
15232 this.picker().addClass('datepicker-dropdown');
15237 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15238 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15239 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15240 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15241 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15242 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15246 fireKey: function(e){
15247 if (!this.picker().isVisible()){
15248 if (e.keyCode == 27) // allow escape to hide and re-show picker
15253 e.preventDefault();
15261 this.onTogglePeriod();
15264 this.onIncrementMinutes();
15267 this.onDecrementMinutes();
15276 onClick: function(e) {
15277 e.stopPropagation();
15278 e.preventDefault();
15281 picker : function()
15283 return this.el.select('.datepicker', true).first();
15286 fillTime: function()
15288 var time = this.pop.select('tbody', true).first();
15290 time.dom.innerHTML = '';
15305 cls: 'hours-up glyphicon glyphicon-chevron-up'
15325 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15346 cls: 'timepicker-hour',
15361 cls: 'timepicker-minute',
15376 cls: 'btn btn-primary period',
15398 cls: 'hours-down glyphicon glyphicon-chevron-down'
15418 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15436 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15443 var hours = this.time.getHours();
15444 var minutes = this.time.getMinutes();
15457 hours = hours - 12;
15461 hours = '0' + hours;
15465 minutes = '0' + minutes;
15468 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15469 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15470 this.pop.select('button', true).first().dom.innerHTML = period;
15476 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15478 var cls = ['bottom'];
15480 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15487 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15492 this.picker().addClass(cls.join('-'));
15496 Roo.each(cls, function(c){
15498 _this.picker().setTop(_this.inputEl().getHeight());
15502 _this.picker().setTop(0 - _this.picker().getHeight());
15507 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15511 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15518 onFocus : function()
15520 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15524 onBlur : function()
15526 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15532 this.picker().show();
15537 this.fireEvent('show', this, this.date);
15542 this.picker().hide();
15545 this.fireEvent('hide', this, this.date);
15548 setTime : function()
15551 this.setValue(this.time.format(this.format));
15553 this.fireEvent('select', this, this.date);
15558 onMousedown: function(e){
15559 e.stopPropagation();
15560 e.preventDefault();
15563 onIncrementHours: function()
15565 Roo.log('onIncrementHours');
15566 this.time = this.time.add(Date.HOUR, 1);
15571 onDecrementHours: function()
15573 Roo.log('onDecrementHours');
15574 this.time = this.time.add(Date.HOUR, -1);
15578 onIncrementMinutes: function()
15580 Roo.log('onIncrementMinutes');
15581 this.time = this.time.add(Date.MINUTE, 1);
15585 onDecrementMinutes: function()
15587 Roo.log('onDecrementMinutes');
15588 this.time = this.time.add(Date.MINUTE, -1);
15592 onTogglePeriod: function()
15594 Roo.log('onTogglePeriod');
15595 this.time = this.time.add(Date.HOUR, 12);
15602 Roo.apply(Roo.bootstrap.TimeField, {
15632 cls: 'btn btn-info ok',
15644 Roo.apply(Roo.bootstrap.TimeField, {
15648 cls: 'datepicker dropdown-menu',
15652 cls: 'datepicker-time',
15656 cls: 'table-condensed',
15658 Roo.bootstrap.TimeField.content,
15659 Roo.bootstrap.TimeField.footer
15678 * @class Roo.bootstrap.CheckBox
15679 * @extends Roo.bootstrap.Input
15680 * Bootstrap CheckBox class
15682 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15683 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15684 * @cfg {String} boxLabel The text that appears beside the checkbox
15685 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15686 * @cfg {Boolean} checked initnal the element
15690 * Create a new CheckBox
15691 * @param {Object} config The config object
15694 Roo.bootstrap.CheckBox = function(config){
15695 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15700 * Fires when the element is checked or unchecked.
15701 * @param {Roo.bootstrap.CheckBox} this This input
15702 * @param {Boolean} checked The new checked value
15708 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15710 inputType: 'checkbox',
15717 getAutoCreate : function()
15719 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15725 cfg.cls = 'form-group checkbox' //input-group
15733 type : this.inputType,
15734 value : (!this.checked) ? this.valueOff : this.inputValue,
15735 cls : 'roo-checkbox', //'form-box',
15736 placeholder : this.placeholder || ''
15740 if (this.weight) { // Validity check?
15741 cfg.cls += " checkbox-" + this.weight;
15744 if (this.disabled) {
15745 input.disabled=true;
15749 input.checked = this.checked;
15753 input.name = this.name;
15757 input.cls += ' input-' + this.size;
15761 ['xs','sm','md','lg'].map(function(size){
15762 if (settings[size]) {
15763 cfg.cls += ' col-' + size + '-' + settings[size];
15769 var inputblock = input;
15774 if (this.before || this.after) {
15777 cls : 'input-group',
15781 inputblock.cn.push({
15783 cls : 'input-group-addon',
15787 inputblock.cn.push(input);
15789 inputblock.cn.push({
15791 cls : 'input-group-addon',
15798 if (align ==='left' && this.fieldLabel.length) {
15799 Roo.log("left and has label");
15805 cls : 'control-label col-md-' + this.labelWidth,
15806 html : this.fieldLabel
15810 cls : "col-md-" + (12 - this.labelWidth),
15817 } else if ( this.fieldLabel.length) {
15822 tag: this.boxLabel ? 'span' : 'label',
15824 cls: 'control-label box-input-label',
15825 //cls : 'input-group-addon',
15826 html : this.fieldLabel
15836 Roo.log(" no label && no align");
15837 cfg.cn = [ inputblock ] ;
15846 html: this.boxLabel
15858 * return the real input element.
15860 inputEl: function ()
15862 return this.el.select('input.roo-checkbox',true).first();
15867 return this.el.select('label.control-label',true).first();
15870 initEvents : function()
15872 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15874 this.inputEl().on('click', this.onClick, this);
15878 onClick : function()
15880 this.setChecked(!this.checked);
15883 setChecked : function(state,suppressEvent)
15885 this.checked = state;
15887 this.inputEl().dom.checked = state;
15889 if(suppressEvent !== true){
15890 this.fireEvent('check', this, state);
15893 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15897 setValue : function(v,suppressEvent)
15899 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15913 * @class Roo.bootstrap.Radio
15914 * @extends Roo.bootstrap.CheckBox
15915 * Bootstrap Radio class
15918 * Create a new Radio
15919 * @param {Object} config The config object
15922 Roo.bootstrap.Radio = function(config){
15923 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15927 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15929 inputType: 'radio',
15933 getAutoCreate : function()
15935 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15941 cfg.cls = 'form-group radio' //input-group
15946 type : this.inputType,
15947 value : (!this.checked) ? this.valueOff : this.inputValue,
15949 placeholder : this.placeholder || ''
15952 if (this.weight) { // Validity check?
15953 cfg.cls += " radio-" + this.weight;
15955 if (this.disabled) {
15956 input.disabled=true;
15960 input.checked = this.checked;
15964 input.name = this.name;
15968 input.cls += ' input-' + this.size;
15972 ['xs','sm','md','lg'].map(function(size){
15973 if (settings[size]) {
15974 cfg.cls += ' col-' + size + '-' + settings[size];
15978 var inputblock = input;
15980 if (this.before || this.after) {
15983 cls : 'input-group',
15987 inputblock.cn.push({
15989 cls : 'input-group-addon',
15993 inputblock.cn.push(input);
15995 inputblock.cn.push({
15997 cls : 'input-group-addon',
16004 if (align ==='left' && this.fieldLabel.length) {
16005 Roo.log("left and has label");
16011 cls : 'control-label col-md-' + this.labelWidth,
16012 html : this.fieldLabel
16016 cls : "col-md-" + (12 - this.labelWidth),
16023 } else if ( this.fieldLabel.length) {
16030 cls: 'control-label box-input-label',
16031 //cls : 'input-group-addon',
16032 html : this.fieldLabel
16042 Roo.log(" no label && no align");
16057 html: this.boxLabel
16064 inputEl: function ()
16066 return this.el.select('input.roo-radio',true).first();
16068 onClick : function()
16070 this.setChecked(true);
16073 setChecked : function(state,suppressEvent)
16076 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16077 v.dom.checked = false;
16081 this.checked = state;
16082 this.inputEl().dom.checked = state;
16084 if(suppressEvent !== true){
16085 this.fireEvent('check', this, state);
16088 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16092 getGroupValue : function()
16095 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16096 if(v.dom.checked == true){
16097 value = v.dom.value;
16105 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16106 * @return {Mixed} value The field value
16108 getValue : function(){
16109 return this.getGroupValue();
16115 //<script type="text/javascript">
16118 * Based Ext JS Library 1.1.1
16119 * Copyright(c) 2006-2007, Ext JS, LLC.
16125 * @class Roo.HtmlEditorCore
16126 * @extends Roo.Component
16127 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16129 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16132 Roo.HtmlEditorCore = function(config){
16135 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16138 * @event initialize
16139 * Fires when the editor is fully initialized (including the iframe)
16140 * @param {Roo.HtmlEditorCore} this
16145 * Fires when the editor is first receives the focus. Any insertion must wait
16146 * until after this event.
16147 * @param {Roo.HtmlEditorCore} this
16151 * @event beforesync
16152 * Fires before the textarea is updated with content from the editor iframe. Return false
16153 * to cancel the sync.
16154 * @param {Roo.HtmlEditorCore} this
16155 * @param {String} html
16159 * @event beforepush
16160 * Fires before the iframe editor is updated with content from the textarea. Return false
16161 * to cancel the push.
16162 * @param {Roo.HtmlEditorCore} this
16163 * @param {String} html
16168 * Fires when the textarea is updated with content from the editor iframe.
16169 * @param {Roo.HtmlEditorCore} this
16170 * @param {String} html
16175 * Fires when the iframe editor is updated with content from the textarea.
16176 * @param {Roo.HtmlEditorCore} this
16177 * @param {String} html
16182 * @event editorevent
16183 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16184 * @param {Roo.HtmlEditorCore} this
16192 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16196 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16202 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16207 * @cfg {Number} height (in pixels)
16211 * @cfg {Number} width (in pixels)
16216 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16219 stylesheets: false,
16224 // private properties
16225 validationEvent : false,
16227 initialized : false,
16229 sourceEditMode : false,
16230 onFocus : Roo.emptyFn,
16232 hideMode:'offsets',
16240 * Protected method that will not generally be called directly. It
16241 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16242 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16244 getDocMarkup : function(){
16247 Roo.log(this.stylesheets);
16249 // inherit styels from page...??
16250 if (this.stylesheets === false) {
16252 Roo.get(document.head).select('style').each(function(node) {
16253 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16256 Roo.get(document.head).select('link').each(function(node) {
16257 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16260 } else if (!this.stylesheets.length) {
16262 st = '<style type="text/css">' +
16263 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16266 Roo.each(this.stylesheets, function(s) {
16267 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16272 st += '<style type="text/css">' +
16273 'IMG { cursor: pointer } ' +
16277 return '<html><head>' + st +
16278 //<style type="text/css">' +
16279 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16281 ' </head><body class="roo-htmleditor-body"></body></html>';
16285 onRender : function(ct, position)
16288 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16289 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16292 this.el.dom.style.border = '0 none';
16293 this.el.dom.setAttribute('tabIndex', -1);
16294 this.el.addClass('x-hidden hide');
16298 if(Roo.isIE){ // fix IE 1px bogus margin
16299 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16303 this.frameId = Roo.id();
16307 var iframe = this.owner.wrap.createChild({
16309 cls: 'form-control', // bootstrap..
16311 name: this.frameId,
16312 frameBorder : 'no',
16313 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16318 this.iframe = iframe.dom;
16320 this.assignDocWin();
16322 this.doc.designMode = 'on';
16325 this.doc.write(this.getDocMarkup());
16329 var task = { // must defer to wait for browser to be ready
16331 //console.log("run task?" + this.doc.readyState);
16332 this.assignDocWin();
16333 if(this.doc.body || this.doc.readyState == 'complete'){
16335 this.doc.designMode="on";
16339 Roo.TaskMgr.stop(task);
16340 this.initEditor.defer(10, this);
16347 Roo.TaskMgr.start(task);
16354 onResize : function(w, h)
16356 Roo.log('resize: ' +w + ',' + h );
16357 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16361 if(typeof w == 'number'){
16363 this.iframe.style.width = w + 'px';
16365 if(typeof h == 'number'){
16367 this.iframe.style.height = h + 'px';
16369 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16376 * Toggles the editor between standard and source edit mode.
16377 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16379 toggleSourceEdit : function(sourceEditMode){
16381 this.sourceEditMode = sourceEditMode === true;
16383 if(this.sourceEditMode){
16385 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16388 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16389 //this.iframe.className = '';
16392 //this.setSize(this.owner.wrap.getSize());
16393 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16400 * Protected method that will not generally be called directly. If you need/want
16401 * custom HTML cleanup, this is the method you should override.
16402 * @param {String} html The HTML to be cleaned
16403 * return {String} The cleaned HTML
16405 cleanHtml : function(html){
16406 html = String(html);
16407 if(html.length > 5){
16408 if(Roo.isSafari){ // strip safari nonsense
16409 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16412 if(html == ' '){
16419 * HTML Editor -> Textarea
16420 * Protected method that will not generally be called directly. Syncs the contents
16421 * of the editor iframe with the textarea.
16423 syncValue : function(){
16424 if(this.initialized){
16425 var bd = (this.doc.body || this.doc.documentElement);
16426 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16427 var html = bd.innerHTML;
16429 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16430 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16432 html = '<div style="'+m[0]+'">' + html + '</div>';
16435 html = this.cleanHtml(html);
16436 // fix up the special chars.. normaly like back quotes in word...
16437 // however we do not want to do this with chinese..
16438 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16439 var cc = b.charCodeAt();
16441 (cc >= 0x4E00 && cc < 0xA000 ) ||
16442 (cc >= 0x3400 && cc < 0x4E00 ) ||
16443 (cc >= 0xf900 && cc < 0xfb00 )
16449 if(this.owner.fireEvent('beforesync', this, html) !== false){
16450 this.el.dom.value = html;
16451 this.owner.fireEvent('sync', this, html);
16457 * Protected method that will not generally be called directly. Pushes the value of the textarea
16458 * into the iframe editor.
16460 pushValue : function(){
16461 if(this.initialized){
16462 var v = this.el.dom.value.trim();
16464 // if(v.length < 1){
16468 if(this.owner.fireEvent('beforepush', this, v) !== false){
16469 var d = (this.doc.body || this.doc.documentElement);
16471 this.cleanUpPaste();
16472 this.el.dom.value = d.innerHTML;
16473 this.owner.fireEvent('push', this, v);
16479 deferFocus : function(){
16480 this.focus.defer(10, this);
16484 focus : function(){
16485 if(this.win && !this.sourceEditMode){
16492 assignDocWin: function()
16494 var iframe = this.iframe;
16497 this.doc = iframe.contentWindow.document;
16498 this.win = iframe.contentWindow;
16500 if (!Roo.get(this.frameId)) {
16503 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16504 this.win = Roo.get(this.frameId).dom.contentWindow;
16509 initEditor : function(){
16510 //console.log("INIT EDITOR");
16511 this.assignDocWin();
16515 this.doc.designMode="on";
16517 this.doc.write(this.getDocMarkup());
16520 var dbody = (this.doc.body || this.doc.documentElement);
16521 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16522 // this copies styles from the containing element into thsi one..
16523 // not sure why we need all of this..
16524 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16526 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16527 //ss['background-attachment'] = 'fixed'; // w3c
16528 dbody.bgProperties = 'fixed'; // ie
16529 //Roo.DomHelper.applyStyles(dbody, ss);
16530 Roo.EventManager.on(this.doc, {
16531 //'mousedown': this.onEditorEvent,
16532 'mouseup': this.onEditorEvent,
16533 'dblclick': this.onEditorEvent,
16534 'click': this.onEditorEvent,
16535 'keyup': this.onEditorEvent,
16540 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16542 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16543 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16545 this.initialized = true;
16547 this.owner.fireEvent('initialize', this);
16552 onDestroy : function(){
16558 //for (var i =0; i < this.toolbars.length;i++) {
16559 // // fixme - ask toolbars for heights?
16560 // this.toolbars[i].onDestroy();
16563 //this.wrap.dom.innerHTML = '';
16564 //this.wrap.remove();
16569 onFirstFocus : function(){
16571 this.assignDocWin();
16574 this.activated = true;
16577 if(Roo.isGecko){ // prevent silly gecko errors
16579 var s = this.win.getSelection();
16580 if(!s.focusNode || s.focusNode.nodeType != 3){
16581 var r = s.getRangeAt(0);
16582 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16587 this.execCmd('useCSS', true);
16588 this.execCmd('styleWithCSS', false);
16591 this.owner.fireEvent('activate', this);
16595 adjustFont: function(btn){
16596 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16597 //if(Roo.isSafari){ // safari
16600 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16601 if(Roo.isSafari){ // safari
16602 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16603 v = (v < 10) ? 10 : v;
16604 v = (v > 48) ? 48 : v;
16605 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16610 v = Math.max(1, v+adjust);
16612 this.execCmd('FontSize', v );
16615 onEditorEvent : function(e){
16616 this.owner.fireEvent('editorevent', this, e);
16617 // this.updateToolbar();
16618 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16621 insertTag : function(tg)
16623 // could be a bit smarter... -> wrap the current selected tRoo..
16624 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16626 range = this.createRange(this.getSelection());
16627 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16628 wrappingNode.appendChild(range.extractContents());
16629 range.insertNode(wrappingNode);
16636 this.execCmd("formatblock", tg);
16640 insertText : function(txt)
16644 var range = this.createRange();
16645 range.deleteContents();
16646 //alert(Sender.getAttribute('label'));
16648 range.insertNode(this.doc.createTextNode(txt));
16654 * Executes a Midas editor command on the editor document and performs necessary focus and
16655 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16656 * @param {String} cmd The Midas command
16657 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16659 relayCmd : function(cmd, value){
16661 this.execCmd(cmd, value);
16662 this.owner.fireEvent('editorevent', this);
16663 //this.updateToolbar();
16664 this.owner.deferFocus();
16668 * Executes a Midas editor command directly on the editor document.
16669 * For visual commands, you should use {@link #relayCmd} instead.
16670 * <b>This should only be called after the editor is initialized.</b>
16671 * @param {String} cmd The Midas command
16672 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16674 execCmd : function(cmd, value){
16675 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16682 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16684 * @param {String} text | dom node..
16686 insertAtCursor : function(text)
16691 if(!this.activated){
16697 var r = this.doc.selection.createRange();
16708 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16712 // from jquery ui (MIT licenced)
16714 var win = this.win;
16716 if (win.getSelection && win.getSelection().getRangeAt) {
16717 range = win.getSelection().getRangeAt(0);
16718 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16719 range.insertNode(node);
16720 } else if (win.document.selection && win.document.selection.createRange) {
16721 // no firefox support
16722 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16723 win.document.selection.createRange().pasteHTML(txt);
16725 // no firefox support
16726 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16727 this.execCmd('InsertHTML', txt);
16736 mozKeyPress : function(e){
16738 var c = e.getCharCode(), cmd;
16741 c = String.fromCharCode(c).toLowerCase();
16755 this.cleanUpPaste.defer(100, this);
16763 e.preventDefault();
16771 fixKeys : function(){ // load time branching for fastest keydown performance
16773 return function(e){
16774 var k = e.getKey(), r;
16777 r = this.doc.selection.createRange();
16780 r.pasteHTML('    ');
16787 r = this.doc.selection.createRange();
16789 var target = r.parentElement();
16790 if(!target || target.tagName.toLowerCase() != 'li'){
16792 r.pasteHTML('<br />');
16798 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16799 this.cleanUpPaste.defer(100, this);
16805 }else if(Roo.isOpera){
16806 return function(e){
16807 var k = e.getKey();
16811 this.execCmd('InsertHTML','    ');
16814 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16815 this.cleanUpPaste.defer(100, this);
16820 }else if(Roo.isSafari){
16821 return function(e){
16822 var k = e.getKey();
16826 this.execCmd('InsertText','\t');
16830 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16831 this.cleanUpPaste.defer(100, this);
16839 getAllAncestors: function()
16841 var p = this.getSelectedNode();
16844 a.push(p); // push blank onto stack..
16845 p = this.getParentElement();
16849 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16853 a.push(this.doc.body);
16857 lastSelNode : false,
16860 getSelection : function()
16862 this.assignDocWin();
16863 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16866 getSelectedNode: function()
16868 // this may only work on Gecko!!!
16870 // should we cache this!!!!
16875 var range = this.createRange(this.getSelection()).cloneRange();
16878 var parent = range.parentElement();
16880 var testRange = range.duplicate();
16881 testRange.moveToElementText(parent);
16882 if (testRange.inRange(range)) {
16885 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16888 parent = parent.parentElement;
16893 // is ancestor a text element.
16894 var ac = range.commonAncestorContainer;
16895 if (ac.nodeType == 3) {
16896 ac = ac.parentNode;
16899 var ar = ac.childNodes;
16902 var other_nodes = [];
16903 var has_other_nodes = false;
16904 for (var i=0;i<ar.length;i++) {
16905 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16908 // fullly contained node.
16910 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16915 // probably selected..
16916 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16917 other_nodes.push(ar[i]);
16921 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16926 has_other_nodes = true;
16928 if (!nodes.length && other_nodes.length) {
16929 nodes= other_nodes;
16931 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16937 createRange: function(sel)
16939 // this has strange effects when using with
16940 // top toolbar - not sure if it's a great idea.
16941 //this.editor.contentWindow.focus();
16942 if (typeof sel != "undefined") {
16944 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16946 return this.doc.createRange();
16949 return this.doc.createRange();
16952 getParentElement: function()
16955 this.assignDocWin();
16956 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16958 var range = this.createRange(sel);
16961 var p = range.commonAncestorContainer;
16962 while (p.nodeType == 3) { // text node
16973 * Range intersection.. the hard stuff...
16977 * [ -- selected range --- ]
16981 * if end is before start or hits it. fail.
16982 * if start is after end or hits it fail.
16984 * if either hits (but other is outside. - then it's not
16990 // @see http://www.thismuchiknow.co.uk/?p=64.
16991 rangeIntersectsNode : function(range, node)
16993 var nodeRange = node.ownerDocument.createRange();
16995 nodeRange.selectNode(node);
16997 nodeRange.selectNodeContents(node);
17000 var rangeStartRange = range.cloneRange();
17001 rangeStartRange.collapse(true);
17003 var rangeEndRange = range.cloneRange();
17004 rangeEndRange.collapse(false);
17006 var nodeStartRange = nodeRange.cloneRange();
17007 nodeStartRange.collapse(true);
17009 var nodeEndRange = nodeRange.cloneRange();
17010 nodeEndRange.collapse(false);
17012 return rangeStartRange.compareBoundaryPoints(
17013 Range.START_TO_START, nodeEndRange) == -1 &&
17014 rangeEndRange.compareBoundaryPoints(
17015 Range.START_TO_START, nodeStartRange) == 1;
17019 rangeCompareNode : function(range, node)
17021 var nodeRange = node.ownerDocument.createRange();
17023 nodeRange.selectNode(node);
17025 nodeRange.selectNodeContents(node);
17029 range.collapse(true);
17031 nodeRange.collapse(true);
17033 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17034 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17036 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17038 var nodeIsBefore = ss == 1;
17039 var nodeIsAfter = ee == -1;
17041 if (nodeIsBefore && nodeIsAfter)
17043 if (!nodeIsBefore && nodeIsAfter)
17044 return 1; //right trailed.
17046 if (nodeIsBefore && !nodeIsAfter)
17047 return 2; // left trailed.
17052 // private? - in a new class?
17053 cleanUpPaste : function()
17055 // cleans up the whole document..
17056 Roo.log('cleanuppaste');
17058 this.cleanUpChildren(this.doc.body);
17059 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17060 if (clean != this.doc.body.innerHTML) {
17061 this.doc.body.innerHTML = clean;
17066 cleanWordChars : function(input) {// change the chars to hex code
17067 var he = Roo.HtmlEditorCore;
17069 var output = input;
17070 Roo.each(he.swapCodes, function(sw) {
17071 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17073 output = output.replace(swapper, sw[1]);
17080 cleanUpChildren : function (n)
17082 if (!n.childNodes.length) {
17085 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17086 this.cleanUpChild(n.childNodes[i]);
17093 cleanUpChild : function (node)
17096 //console.log(node);
17097 if (node.nodeName == "#text") {
17098 // clean up silly Windows -- stuff?
17101 if (node.nodeName == "#comment") {
17102 node.parentNode.removeChild(node);
17103 // clean up silly Windows -- stuff?
17107 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17109 node.parentNode.removeChild(node);
17114 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17116 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17117 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17119 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17120 // remove_keep_children = true;
17123 if (remove_keep_children) {
17124 this.cleanUpChildren(node);
17125 // inserts everything just before this node...
17126 while (node.childNodes.length) {
17127 var cn = node.childNodes[0];
17128 node.removeChild(cn);
17129 node.parentNode.insertBefore(cn, node);
17131 node.parentNode.removeChild(node);
17135 if (!node.attributes || !node.attributes.length) {
17136 this.cleanUpChildren(node);
17140 function cleanAttr(n,v)
17143 if (v.match(/^\./) || v.match(/^\//)) {
17146 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17149 if (v.match(/^#/)) {
17152 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17153 node.removeAttribute(n);
17157 function cleanStyle(n,v)
17159 if (v.match(/expression/)) { //XSS?? should we even bother..
17160 node.removeAttribute(n);
17163 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17164 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17167 var parts = v.split(/;/);
17170 Roo.each(parts, function(p) {
17171 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17175 var l = p.split(':').shift().replace(/\s+/g,'');
17176 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17178 if ( cblack.indexOf(l) > -1) {
17179 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17180 //node.removeAttribute(n);
17184 // only allow 'c whitelisted system attributes'
17185 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17186 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17187 //node.removeAttribute(n);
17197 if (clean.length) {
17198 node.setAttribute(n, clean.join(';'));
17200 node.removeAttribute(n);
17206 for (var i = node.attributes.length-1; i > -1 ; i--) {
17207 var a = node.attributes[i];
17210 if (a.name.toLowerCase().substr(0,2)=='on') {
17211 node.removeAttribute(a.name);
17214 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17215 node.removeAttribute(a.name);
17218 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17219 cleanAttr(a.name,a.value); // fixme..
17222 if (a.name == 'style') {
17223 cleanStyle(a.name,a.value);
17226 /// clean up MS crap..
17227 // tecnically this should be a list of valid class'es..
17230 if (a.name == 'class') {
17231 if (a.value.match(/^Mso/)) {
17232 node.className = '';
17235 if (a.value.match(/body/)) {
17236 node.className = '';
17247 this.cleanUpChildren(node);
17252 * Clean up MS wordisms...
17254 cleanWord : function(node)
17257 var cleanWordChildren = function()
17259 if (!node.childNodes.length) {
17262 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17263 _t.cleanWord(node.childNodes[i]);
17269 this.cleanWord(this.doc.body);
17272 if (node.nodeName == "#text") {
17273 // clean up silly Windows -- stuff?
17276 if (node.nodeName == "#comment") {
17277 node.parentNode.removeChild(node);
17278 // clean up silly Windows -- stuff?
17282 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17283 node.parentNode.removeChild(node);
17287 // remove - but keep children..
17288 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17289 while (node.childNodes.length) {
17290 var cn = node.childNodes[0];
17291 node.removeChild(cn);
17292 node.parentNode.insertBefore(cn, node);
17294 node.parentNode.removeChild(node);
17295 cleanWordChildren();
17299 if (node.className.length) {
17301 var cn = node.className.split(/\W+/);
17303 Roo.each(cn, function(cls) {
17304 if (cls.match(/Mso[a-zA-Z]+/)) {
17309 node.className = cna.length ? cna.join(' ') : '';
17311 node.removeAttribute("class");
17315 if (node.hasAttribute("lang")) {
17316 node.removeAttribute("lang");
17319 if (node.hasAttribute("style")) {
17321 var styles = node.getAttribute("style").split(";");
17323 Roo.each(styles, function(s) {
17324 if (!s.match(/:/)) {
17327 var kv = s.split(":");
17328 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17331 // what ever is left... we allow.
17334 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17335 if (!nstyle.length) {
17336 node.removeAttribute('style');
17340 cleanWordChildren();
17344 domToHTML : function(currentElement, depth, nopadtext) {
17346 depth = depth || 0;
17347 nopadtext = nopadtext || false;
17349 if (!currentElement) {
17350 return this.domToHTML(this.doc.body);
17353 //Roo.log(currentElement);
17355 var allText = false;
17356 var nodeName = currentElement.nodeName;
17357 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17359 if (nodeName == '#text') {
17360 return currentElement.nodeValue;
17365 if (nodeName != 'BODY') {
17368 // Prints the node tagName, such as <A>, <IMG>, etc
17371 for(i = 0; i < currentElement.attributes.length;i++) {
17373 var aname = currentElement.attributes.item(i).name;
17374 if (!currentElement.attributes.item(i).value.length) {
17377 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17380 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17389 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17392 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17397 // Traverse the tree
17399 var currentElementChild = currentElement.childNodes.item(i);
17400 var allText = true;
17401 var innerHTML = '';
17403 while (currentElementChild) {
17404 // Formatting code (indent the tree so it looks nice on the screen)
17405 var nopad = nopadtext;
17406 if (lastnode == 'SPAN') {
17410 if (currentElementChild.nodeName == '#text') {
17411 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17412 if (!nopad && toadd.length > 80) {
17413 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17415 innerHTML += toadd;
17418 currentElementChild = currentElement.childNodes.item(i);
17424 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17426 // Recursively traverse the tree structure of the child node
17427 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17428 lastnode = currentElementChild.nodeName;
17430 currentElementChild=currentElement.childNodes.item(i);
17436 // The remaining code is mostly for formatting the tree
17437 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17442 ret+= "</"+tagName+">";
17448 // hide stuff that is not compatible
17462 * @event specialkey
17466 * @cfg {String} fieldClass @hide
17469 * @cfg {String} focusClass @hide
17472 * @cfg {String} autoCreate @hide
17475 * @cfg {String} inputType @hide
17478 * @cfg {String} invalidClass @hide
17481 * @cfg {String} invalidText @hide
17484 * @cfg {String} msgFx @hide
17487 * @cfg {String} validateOnBlur @hide
17491 Roo.HtmlEditorCore.white = [
17492 'area', 'br', 'img', 'input', 'hr', 'wbr',
17494 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17495 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17496 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17497 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17498 'table', 'ul', 'xmp',
17500 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17503 'dir', 'menu', 'ol', 'ul', 'dl',
17509 Roo.HtmlEditorCore.black = [
17510 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17512 'base', 'basefont', 'bgsound', 'blink', 'body',
17513 'frame', 'frameset', 'head', 'html', 'ilayer',
17514 'iframe', 'layer', 'link', 'meta', 'object',
17515 'script', 'style' ,'title', 'xml' // clean later..
17517 Roo.HtmlEditorCore.clean = [
17518 'script', 'style', 'title', 'xml'
17520 Roo.HtmlEditorCore.remove = [
17525 Roo.HtmlEditorCore.ablack = [
17529 Roo.HtmlEditorCore.aclean = [
17530 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17534 Roo.HtmlEditorCore.pwhite= [
17535 'http', 'https', 'mailto'
17538 // white listed style attributes.
17539 Roo.HtmlEditorCore.cwhite= [
17540 // 'text-align', /// default is to allow most things..
17546 // black listed style attributes.
17547 Roo.HtmlEditorCore.cblack= [
17548 // 'font-size' -- this can be set by the project
17552 Roo.HtmlEditorCore.swapCodes =[
17571 * @class Roo.bootstrap.HtmlEditor
17572 * @extends Roo.bootstrap.TextArea
17573 * Bootstrap HtmlEditor class
17576 * Create a new HtmlEditor
17577 * @param {Object} config The config object
17580 Roo.bootstrap.HtmlEditor = function(config){
17581 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17582 if (!this.toolbars) {
17583 this.toolbars = [];
17585 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17588 * @event initialize
17589 * Fires when the editor is fully initialized (including the iframe)
17590 * @param {HtmlEditor} this
17595 * Fires when the editor is first receives the focus. Any insertion must wait
17596 * until after this event.
17597 * @param {HtmlEditor} this
17601 * @event beforesync
17602 * Fires before the textarea is updated with content from the editor iframe. Return false
17603 * to cancel the sync.
17604 * @param {HtmlEditor} this
17605 * @param {String} html
17609 * @event beforepush
17610 * Fires before the iframe editor is updated with content from the textarea. Return false
17611 * to cancel the push.
17612 * @param {HtmlEditor} this
17613 * @param {String} html
17618 * Fires when the textarea is updated with content from the editor iframe.
17619 * @param {HtmlEditor} this
17620 * @param {String} html
17625 * Fires when the iframe editor is updated with content from the textarea.
17626 * @param {HtmlEditor} this
17627 * @param {String} html
17631 * @event editmodechange
17632 * Fires when the editor switches edit modes
17633 * @param {HtmlEditor} this
17634 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17636 editmodechange: true,
17638 * @event editorevent
17639 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17640 * @param {HtmlEditor} this
17644 * @event firstfocus
17645 * Fires when on first focus - needed by toolbars..
17646 * @param {HtmlEditor} this
17651 * Auto save the htmlEditor value as a file into Events
17652 * @param {HtmlEditor} this
17656 * @event savedpreview
17657 * preview the saved version of htmlEditor
17658 * @param {HtmlEditor} this
17665 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17669 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17674 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17679 * @cfg {Number} height (in pixels)
17683 * @cfg {Number} width (in pixels)
17688 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17691 stylesheets: false,
17696 // private properties
17697 validationEvent : false,
17699 initialized : false,
17702 onFocus : Roo.emptyFn,
17704 hideMode:'offsets',
17707 tbContainer : false,
17709 toolbarContainer :function() {
17710 return this.wrap.select('.x-html-editor-tb',true).first();
17714 * Protected method that will not generally be called directly. It
17715 * is called when the editor creates its toolbar. Override this method if you need to
17716 * add custom toolbar buttons.
17717 * @param {HtmlEditor} editor
17719 createToolbar : function(){
17721 Roo.log("create toolbars");
17723 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17724 this.toolbars[0].render(this.toolbarContainer());
17728 // if (!editor.toolbars || !editor.toolbars.length) {
17729 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17732 // for (var i =0 ; i < editor.toolbars.length;i++) {
17733 // editor.toolbars[i] = Roo.factory(
17734 // typeof(editor.toolbars[i]) == 'string' ?
17735 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17736 // Roo.bootstrap.HtmlEditor);
17737 // editor.toolbars[i].init(editor);
17743 onRender : function(ct, position)
17745 // Roo.log("Call onRender: " + this.xtype);
17747 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17749 this.wrap = this.inputEl().wrap({
17750 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17753 this.editorcore.onRender(ct, position);
17755 if (this.resizable) {
17756 this.resizeEl = new Roo.Resizable(this.wrap, {
17760 minHeight : this.height,
17761 height: this.height,
17762 handles : this.resizable,
17765 resize : function(r, w, h) {
17766 _t.onResize(w,h); // -something
17772 this.createToolbar(this);
17775 if(!this.width && this.resizable){
17776 this.setSize(this.wrap.getSize());
17778 if (this.resizeEl) {
17779 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17780 // should trigger onReize..
17786 onResize : function(w, h)
17788 Roo.log('resize: ' +w + ',' + h );
17789 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17793 if(this.inputEl() ){
17794 if(typeof w == 'number'){
17795 var aw = w - this.wrap.getFrameWidth('lr');
17796 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17799 if(typeof h == 'number'){
17800 var tbh = -11; // fixme it needs to tool bar size!
17801 for (var i =0; i < this.toolbars.length;i++) {
17802 // fixme - ask toolbars for heights?
17803 tbh += this.toolbars[i].el.getHeight();
17804 //if (this.toolbars[i].footer) {
17805 // tbh += this.toolbars[i].footer.el.getHeight();
17813 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17814 ah -= 5; // knock a few pixes off for look..
17815 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17819 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17820 this.editorcore.onResize(ew,eh);
17825 * Toggles the editor between standard and source edit mode.
17826 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17828 toggleSourceEdit : function(sourceEditMode)
17830 this.editorcore.toggleSourceEdit(sourceEditMode);
17832 if(this.editorcore.sourceEditMode){
17833 Roo.log('editor - showing textarea');
17836 // Roo.log(this.syncValue());
17838 this.inputEl().removeClass(['hide', 'x-hidden']);
17839 this.inputEl().dom.removeAttribute('tabIndex');
17840 this.inputEl().focus();
17842 Roo.log('editor - hiding textarea');
17844 // Roo.log(this.pushValue());
17847 this.inputEl().addClass(['hide', 'x-hidden']);
17848 this.inputEl().dom.setAttribute('tabIndex', -1);
17849 //this.deferFocus();
17852 if(this.resizable){
17853 this.setSize(this.wrap.getSize());
17856 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17859 // private (for BoxComponent)
17860 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17862 // private (for BoxComponent)
17863 getResizeEl : function(){
17867 // private (for BoxComponent)
17868 getPositionEl : function(){
17873 initEvents : function(){
17874 this.originalValue = this.getValue();
17878 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17881 // markInvalid : Roo.emptyFn,
17883 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17886 // clearInvalid : Roo.emptyFn,
17888 setValue : function(v){
17889 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17890 this.editorcore.pushValue();
17895 deferFocus : function(){
17896 this.focus.defer(10, this);
17900 focus : function(){
17901 this.editorcore.focus();
17907 onDestroy : function(){
17913 for (var i =0; i < this.toolbars.length;i++) {
17914 // fixme - ask toolbars for heights?
17915 this.toolbars[i].onDestroy();
17918 this.wrap.dom.innerHTML = '';
17919 this.wrap.remove();
17924 onFirstFocus : function(){
17925 //Roo.log("onFirstFocus");
17926 this.editorcore.onFirstFocus();
17927 for (var i =0; i < this.toolbars.length;i++) {
17928 this.toolbars[i].onFirstFocus();
17934 syncValue : function()
17936 this.editorcore.syncValue();
17939 pushValue : function()
17941 this.editorcore.pushValue();
17945 // hide stuff that is not compatible
17959 * @event specialkey
17963 * @cfg {String} fieldClass @hide
17966 * @cfg {String} focusClass @hide
17969 * @cfg {String} autoCreate @hide
17972 * @cfg {String} inputType @hide
17975 * @cfg {String} invalidClass @hide
17978 * @cfg {String} invalidText @hide
17981 * @cfg {String} msgFx @hide
17984 * @cfg {String} validateOnBlur @hide
17993 Roo.namespace('Roo.bootstrap.htmleditor');
17995 * @class Roo.bootstrap.HtmlEditorToolbar1
18000 new Roo.bootstrap.HtmlEditor({
18003 new Roo.bootstrap.HtmlEditorToolbar1({
18004 disable : { fonts: 1 , format: 1, ..., ... , ...],
18010 * @cfg {Object} disable List of elements to disable..
18011 * @cfg {Array} btns List of additional buttons.
18015 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18018 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18021 Roo.apply(this, config);
18023 // default disabled, based on 'good practice'..
18024 this.disable = this.disable || {};
18025 Roo.applyIf(this.disable, {
18028 specialElements : true
18030 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18032 this.editor = config.editor;
18033 this.editorcore = config.editor.editorcore;
18035 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18037 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18038 // dont call parent... till later.
18040 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18045 editorcore : false,
18050 "h1","h2","h3","h4","h5","h6",
18052 "abbr", "acronym", "address", "cite", "samp", "var",
18056 onRender : function(ct, position)
18058 // Roo.log("Call onRender: " + this.xtype);
18060 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18062 this.el.dom.style.marginBottom = '0';
18064 var editorcore = this.editorcore;
18065 var editor= this.editor;
18068 var btn = function(id,cmd , toggle, handler){
18070 var event = toggle ? 'toggle' : 'click';
18075 xns: Roo.bootstrap,
18078 enableToggle:toggle !== false,
18080 pressed : toggle ? false : null,
18083 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18084 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18093 xns: Roo.bootstrap,
18094 glyphicon : 'font',
18098 xns: Roo.bootstrap,
18102 Roo.each(this.formats, function(f) {
18103 style.menu.items.push({
18105 xns: Roo.bootstrap,
18106 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18111 editorcore.insertTag(this.tagname);
18118 children.push(style);
18121 btn('bold',false,true);
18122 btn('italic',false,true);
18123 btn('align-left', 'justifyleft',true);
18124 btn('align-center', 'justifycenter',true);
18125 btn('align-right' , 'justifyright',true);
18126 btn('link', false, false, function(btn) {
18127 //Roo.log("create link?");
18128 var url = prompt(this.createLinkText, this.defaultLinkValue);
18129 if(url && url != 'http:/'+'/'){
18130 this.editorcore.relayCmd('createlink', url);
18133 btn('list','insertunorderedlist',true);
18134 btn('pencil', false,true, function(btn){
18137 this.toggleSourceEdit(btn.pressed);
18143 xns: Roo.bootstrap,
18148 xns: Roo.bootstrap,
18153 cog.menu.items.push({
18155 xns: Roo.bootstrap,
18156 html : Clean styles,
18161 editorcore.insertTag(this.tagname);
18170 this.xtype = 'NavSimplebar';
18172 for(var i=0;i< children.length;i++) {
18174 this.buttons.add(this.addxtypeChild(children[i]));
18178 editor.on('editorevent', this.updateToolbar, this);
18180 onBtnClick : function(id)
18182 this.editorcore.relayCmd(id);
18183 this.editorcore.focus();
18187 * Protected method that will not generally be called directly. It triggers
18188 * a toolbar update by reading the markup state of the current selection in the editor.
18190 updateToolbar: function(){
18192 if(!this.editorcore.activated){
18193 this.editor.onFirstFocus(); // is this neeed?
18197 var btns = this.buttons;
18198 var doc = this.editorcore.doc;
18199 btns.get('bold').setActive(doc.queryCommandState('bold'));
18200 btns.get('italic').setActive(doc.queryCommandState('italic'));
18201 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18203 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18204 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18205 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18207 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18208 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18211 var ans = this.editorcore.getAllAncestors();
18212 if (this.formatCombo) {
18215 var store = this.formatCombo.store;
18216 this.formatCombo.setValue("");
18217 for (var i =0; i < ans.length;i++) {
18218 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18220 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18228 // hides menus... - so this cant be on a menu...
18229 Roo.bootstrap.MenuMgr.hideAll();
18231 Roo.bootstrap.MenuMgr.hideAll();
18232 //this.editorsyncValue();
18234 onFirstFocus: function() {
18235 this.buttons.each(function(item){
18239 toggleSourceEdit : function(sourceEditMode){
18242 if(sourceEditMode){
18243 Roo.log("disabling buttons");
18244 this.buttons.each( function(item){
18245 if(item.cmd != 'pencil'){
18251 Roo.log("enabling buttons");
18252 if(this.editorcore.initialized){
18253 this.buttons.each( function(item){
18259 Roo.log("calling toggole on editor");
18260 // tell the editor that it's been pressed..
18261 this.editor.toggleSourceEdit(sourceEditMode);
18271 * @class Roo.bootstrap.Table.AbstractSelectionModel
18272 * @extends Roo.util.Observable
18273 * Abstract base class for grid SelectionModels. It provides the interface that should be
18274 * implemented by descendant classes. This class should not be directly instantiated.
18277 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18278 this.locked = false;
18279 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18283 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18284 /** @ignore Called by the grid automatically. Do not call directly. */
18285 init : function(grid){
18291 * Locks the selections.
18294 this.locked = true;
18298 * Unlocks the selections.
18300 unlock : function(){
18301 this.locked = false;
18305 * Returns true if the selections are locked.
18306 * @return {Boolean}
18308 isLocked : function(){
18309 return this.locked;
18313 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18314 * @class Roo.bootstrap.Table.RowSelectionModel
18315 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18316 * It supports multiple selections and keyboard selection/navigation.
18318 * @param {Object} config
18321 Roo.bootstrap.Table.RowSelectionModel = function(config){
18322 Roo.apply(this, config);
18323 this.selections = new Roo.util.MixedCollection(false, function(o){
18328 this.lastActive = false;
18332 * @event selectionchange
18333 * Fires when the selection changes
18334 * @param {SelectionModel} this
18336 "selectionchange" : true,
18338 * @event afterselectionchange
18339 * Fires after the selection changes (eg. by key press or clicking)
18340 * @param {SelectionModel} this
18342 "afterselectionchange" : true,
18344 * @event beforerowselect
18345 * Fires when a row is selected being selected, return false to cancel.
18346 * @param {SelectionModel} this
18347 * @param {Number} rowIndex The selected index
18348 * @param {Boolean} keepExisting False if other selections will be cleared
18350 "beforerowselect" : true,
18353 * Fires when a row is selected.
18354 * @param {SelectionModel} this
18355 * @param {Number} rowIndex The selected index
18356 * @param {Roo.data.Record} r The record
18358 "rowselect" : true,
18360 * @event rowdeselect
18361 * Fires when a row is deselected.
18362 * @param {SelectionModel} this
18363 * @param {Number} rowIndex The selected index
18365 "rowdeselect" : true
18367 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18368 this.locked = false;
18371 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18373 * @cfg {Boolean} singleSelect
18374 * True to allow selection of only one row at a time (defaults to false)
18376 singleSelect : false,
18379 initEvents : function(){
18381 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18382 this.grid.on("mousedown", this.handleMouseDown, this);
18383 }else{ // allow click to work like normal
18384 this.grid.on("rowclick", this.handleDragableRowClick, this);
18387 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18388 "up" : function(e){
18390 this.selectPrevious(e.shiftKey);
18391 }else if(this.last !== false && this.lastActive !== false){
18392 var last = this.last;
18393 this.selectRange(this.last, this.lastActive-1);
18394 this.grid.getView().focusRow(this.lastActive);
18395 if(last !== false){
18399 this.selectFirstRow();
18401 this.fireEvent("afterselectionchange", this);
18403 "down" : function(e){
18405 this.selectNext(e.shiftKey);
18406 }else if(this.last !== false && this.lastActive !== false){
18407 var last = this.last;
18408 this.selectRange(this.last, this.lastActive+1);
18409 this.grid.getView().focusRow(this.lastActive);
18410 if(last !== false){
18414 this.selectFirstRow();
18416 this.fireEvent("afterselectionchange", this);
18421 var view = this.grid.view;
18422 view.on("refresh", this.onRefresh, this);
18423 view.on("rowupdated", this.onRowUpdated, this);
18424 view.on("rowremoved", this.onRemove, this);
18428 onRefresh : function(){
18429 var ds = this.grid.dataSource, i, v = this.grid.view;
18430 var s = this.selections;
18431 s.each(function(r){
18432 if((i = ds.indexOfId(r.id)) != -1){
18441 onRemove : function(v, index, r){
18442 this.selections.remove(r);
18446 onRowUpdated : function(v, index, r){
18447 if(this.isSelected(r)){
18448 v.onRowSelect(index);
18454 * @param {Array} records The records to select
18455 * @param {Boolean} keepExisting (optional) True to keep existing selections
18457 selectRecords : function(records, keepExisting){
18459 this.clearSelections();
18461 var ds = this.grid.dataSource;
18462 for(var i = 0, len = records.length; i < len; i++){
18463 this.selectRow(ds.indexOf(records[i]), true);
18468 * Gets the number of selected rows.
18471 getCount : function(){
18472 return this.selections.length;
18476 * Selects the first row in the grid.
18478 selectFirstRow : function(){
18483 * Select the last row.
18484 * @param {Boolean} keepExisting (optional) True to keep existing selections
18486 selectLastRow : function(keepExisting){
18487 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18491 * Selects the row immediately following the last selected row.
18492 * @param {Boolean} keepExisting (optional) True to keep existing selections
18494 selectNext : function(keepExisting){
18495 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18496 this.selectRow(this.last+1, keepExisting);
18497 this.grid.getView().focusRow(this.last);
18502 * Selects the row that precedes the last selected row.
18503 * @param {Boolean} keepExisting (optional) True to keep existing selections
18505 selectPrevious : function(keepExisting){
18507 this.selectRow(this.last-1, keepExisting);
18508 this.grid.getView().focusRow(this.last);
18513 * Returns the selected records
18514 * @return {Array} Array of selected records
18516 getSelections : function(){
18517 return [].concat(this.selections.items);
18521 * Returns the first selected record.
18524 getSelected : function(){
18525 return this.selections.itemAt(0);
18530 * Clears all selections.
18532 clearSelections : function(fast){
18533 if(this.locked) return;
18535 var ds = this.grid.dataSource;
18536 var s = this.selections;
18537 s.each(function(r){
18538 this.deselectRow(ds.indexOfId(r.id));
18542 this.selections.clear();
18549 * Selects all rows.
18551 selectAll : function(){
18552 if(this.locked) return;
18553 this.selections.clear();
18554 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18555 this.selectRow(i, true);
18560 * Returns True if there is a selection.
18561 * @return {Boolean}
18563 hasSelection : function(){
18564 return this.selections.length > 0;
18568 * Returns True if the specified row is selected.
18569 * @param {Number/Record} record The record or index of the record to check
18570 * @return {Boolean}
18572 isSelected : function(index){
18573 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18574 return (r && this.selections.key(r.id) ? true : false);
18578 * Returns True if the specified record id is selected.
18579 * @param {String} id The id of record to check
18580 * @return {Boolean}
18582 isIdSelected : function(id){
18583 return (this.selections.key(id) ? true : false);
18587 handleMouseDown : function(e, t){
18588 var view = this.grid.getView(), rowIndex;
18589 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18592 if(e.shiftKey && this.last !== false){
18593 var last = this.last;
18594 this.selectRange(last, rowIndex, e.ctrlKey);
18595 this.last = last; // reset the last
18596 view.focusRow(rowIndex);
18598 var isSelected = this.isSelected(rowIndex);
18599 if(e.button !== 0 && isSelected){
18600 view.focusRow(rowIndex);
18601 }else if(e.ctrlKey && isSelected){
18602 this.deselectRow(rowIndex);
18603 }else if(!isSelected){
18604 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18605 view.focusRow(rowIndex);
18608 this.fireEvent("afterselectionchange", this);
18611 handleDragableRowClick : function(grid, rowIndex, e)
18613 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18614 this.selectRow(rowIndex, false);
18615 grid.view.focusRow(rowIndex);
18616 this.fireEvent("afterselectionchange", this);
18621 * Selects multiple rows.
18622 * @param {Array} rows Array of the indexes of the row to select
18623 * @param {Boolean} keepExisting (optional) True to keep existing selections
18625 selectRows : function(rows, keepExisting){
18627 this.clearSelections();
18629 for(var i = 0, len = rows.length; i < len; i++){
18630 this.selectRow(rows[i], true);
18635 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18636 * @param {Number} startRow The index of the first row in the range
18637 * @param {Number} endRow The index of the last row in the range
18638 * @param {Boolean} keepExisting (optional) True to retain existing selections
18640 selectRange : function(startRow, endRow, keepExisting){
18641 if(this.locked) return;
18643 this.clearSelections();
18645 if(startRow <= endRow){
18646 for(var i = startRow; i <= endRow; i++){
18647 this.selectRow(i, true);
18650 for(var i = startRow; i >= endRow; i--){
18651 this.selectRow(i, true);
18657 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18658 * @param {Number} startRow The index of the first row in the range
18659 * @param {Number} endRow The index of the last row in the range
18661 deselectRange : function(startRow, endRow, preventViewNotify){
18662 if(this.locked) return;
18663 for(var i = startRow; i <= endRow; i++){
18664 this.deselectRow(i, preventViewNotify);
18670 * @param {Number} row The index of the row to select
18671 * @param {Boolean} keepExisting (optional) True to keep existing selections
18673 selectRow : function(index, keepExisting, preventViewNotify){
18674 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18675 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18676 if(!keepExisting || this.singleSelect){
18677 this.clearSelections();
18679 var r = this.grid.dataSource.getAt(index);
18680 this.selections.add(r);
18681 this.last = this.lastActive = index;
18682 if(!preventViewNotify){
18683 this.grid.getView().onRowSelect(index);
18685 this.fireEvent("rowselect", this, index, r);
18686 this.fireEvent("selectionchange", this);
18692 * @param {Number} row The index of the row to deselect
18694 deselectRow : function(index, preventViewNotify){
18695 if(this.locked) return;
18696 if(this.last == index){
18699 if(this.lastActive == index){
18700 this.lastActive = false;
18702 var r = this.grid.dataSource.getAt(index);
18703 this.selections.remove(r);
18704 if(!preventViewNotify){
18705 this.grid.getView().onRowDeselect(index);
18707 this.fireEvent("rowdeselect", this, index);
18708 this.fireEvent("selectionchange", this);
18712 restoreLast : function(){
18714 this.last = this._last;
18719 acceptsNav : function(row, col, cm){
18720 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18724 onEditorKey : function(field, e){
18725 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18730 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18732 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18734 }else if(k == e.ENTER && !e.ctrlKey){
18738 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18740 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18742 }else if(k == e.ESC){
18746 g.startEditing(newCell[0], newCell[1]);
18751 * Ext JS Library 1.1.1
18752 * Copyright(c) 2006-2007, Ext JS, LLC.
18754 * Originally Released Under LGPL - original licence link has changed is not relivant.
18757 * <script type="text/javascript">
18761 * @class Roo.bootstrap.PagingToolbar
18763 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18765 * Create a new PagingToolbar
18766 * @param {Object} config The config object
18768 Roo.bootstrap.PagingToolbar = function(config)
18770 // old args format still supported... - xtype is prefered..
18771 // created from xtype...
18772 var ds = config.dataSource;
18773 this.toolbarItems = [];
18774 if (config.items) {
18775 this.toolbarItems = config.items;
18776 // config.items = [];
18779 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18786 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18790 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18792 * @cfg {Roo.data.Store} dataSource
18793 * The underlying data store providing the paged data
18796 * @cfg {String/HTMLElement/Element} container
18797 * container The id or element that will contain the toolbar
18800 * @cfg {Boolean} displayInfo
18801 * True to display the displayMsg (defaults to false)
18804 * @cfg {Number} pageSize
18805 * The number of records to display per page (defaults to 20)
18809 * @cfg {String} displayMsg
18810 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18812 displayMsg : 'Displaying {0} - {1} of {2}',
18814 * @cfg {String} emptyMsg
18815 * The message to display when no records are found (defaults to "No data to display")
18817 emptyMsg : 'No data to display',
18819 * Customizable piece of the default paging text (defaults to "Page")
18822 beforePageText : "Page",
18824 * Customizable piece of the default paging text (defaults to "of %0")
18827 afterPageText : "of {0}",
18829 * Customizable piece of the default paging text (defaults to "First Page")
18832 firstText : "First Page",
18834 * Customizable piece of the default paging text (defaults to "Previous Page")
18837 prevText : "Previous Page",
18839 * Customizable piece of the default paging text (defaults to "Next Page")
18842 nextText : "Next Page",
18844 * Customizable piece of the default paging text (defaults to "Last Page")
18847 lastText : "Last Page",
18849 * Customizable piece of the default paging text (defaults to "Refresh")
18852 refreshText : "Refresh",
18856 onRender : function(ct, position)
18858 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18859 this.navgroup.parentId = this.id;
18860 this.navgroup.onRender(this.el, null);
18861 // add the buttons to the navgroup
18863 if(this.displayInfo){
18864 Roo.log(this.el.select('ul.navbar-nav',true).first());
18865 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18866 this.displayEl = this.el.select('.x-paging-info', true).first();
18867 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18868 // this.displayEl = navel.el.select('span',true).first();
18874 Roo.each(_this.buttons, function(e){
18875 Roo.factory(e).onRender(_this.el, null);
18879 Roo.each(_this.toolbarItems, function(e) {
18880 _this.navgroup.addItem(e);
18883 this.first = this.navgroup.addItem({
18884 tooltip: this.firstText,
18886 icon : 'fa fa-backward',
18888 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18891 this.prev = this.navgroup.addItem({
18892 tooltip: this.prevText,
18894 icon : 'fa fa-step-backward',
18896 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18898 //this.addSeparator();
18901 var field = this.navgroup.addItem( {
18903 cls : 'x-paging-position',
18905 html : this.beforePageText +
18906 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18907 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18910 this.field = field.el.select('input', true).first();
18911 this.field.on("keydown", this.onPagingKeydown, this);
18912 this.field.on("focus", function(){this.dom.select();});
18915 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18916 //this.field.setHeight(18);
18917 //this.addSeparator();
18918 this.next = this.navgroup.addItem({
18919 tooltip: this.nextText,
18921 html : ' <i class="fa fa-step-forward">',
18923 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18925 this.last = this.navgroup.addItem({
18926 tooltip: this.lastText,
18927 icon : 'fa fa-forward',
18930 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18932 //this.addSeparator();
18933 this.loading = this.navgroup.addItem({
18934 tooltip: this.refreshText,
18935 icon: 'fa fa-refresh',
18937 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18943 updateInfo : function(){
18944 if(this.displayEl){
18945 var count = this.ds.getCount();
18946 var msg = count == 0 ?
18950 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18952 this.displayEl.update(msg);
18957 onLoad : function(ds, r, o){
18958 this.cursor = o.params ? o.params.start : 0;
18959 var d = this.getPageData(),
18963 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18964 this.field.dom.value = ap;
18965 this.first.setDisabled(ap == 1);
18966 this.prev.setDisabled(ap == 1);
18967 this.next.setDisabled(ap == ps);
18968 this.last.setDisabled(ap == ps);
18969 this.loading.enable();
18974 getPageData : function(){
18975 var total = this.ds.getTotalCount();
18978 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18979 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18984 onLoadError : function(){
18985 this.loading.enable();
18989 onPagingKeydown : function(e){
18990 var k = e.getKey();
18991 var d = this.getPageData();
18993 var v = this.field.dom.value, pageNum;
18994 if(!v || isNaN(pageNum = parseInt(v, 10))){
18995 this.field.dom.value = d.activePage;
18998 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18999 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19002 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))
19004 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19005 this.field.dom.value = pageNum;
19006 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19009 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19011 var v = this.field.dom.value, pageNum;
19012 var increment = (e.shiftKey) ? 10 : 1;
19013 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19015 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19016 this.field.dom.value = d.activePage;
19019 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19021 this.field.dom.value = parseInt(v, 10) + increment;
19022 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19023 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19030 beforeLoad : function(){
19032 this.loading.disable();
19037 onClick : function(which){
19044 ds.load({params:{start: 0, limit: this.pageSize}});
19047 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19050 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19053 var total = ds.getTotalCount();
19054 var extra = total % this.pageSize;
19055 var lastStart = extra ? (total - extra) : total-this.pageSize;
19056 ds.load({params:{start: lastStart, limit: this.pageSize}});
19059 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19065 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19066 * @param {Roo.data.Store} store The data store to unbind
19068 unbind : function(ds){
19069 ds.un("beforeload", this.beforeLoad, this);
19070 ds.un("load", this.onLoad, this);
19071 ds.un("loadexception", this.onLoadError, this);
19072 ds.un("remove", this.updateInfo, this);
19073 ds.un("add", this.updateInfo, this);
19074 this.ds = undefined;
19078 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19079 * @param {Roo.data.Store} store The data store to bind
19081 bind : function(ds){
19082 ds.on("beforeload", this.beforeLoad, this);
19083 ds.on("load", this.onLoad, this);
19084 ds.on("loadexception", this.onLoadError, this);
19085 ds.on("remove", this.updateInfo, this);
19086 ds.on("add", this.updateInfo, this);
19097 * @class Roo.bootstrap.MessageBar
19098 * @extends Roo.bootstrap.Component
19099 * Bootstrap MessageBar class
19100 * @cfg {String} html contents of the MessageBar
19101 * @cfg {String} weight (info | success | warning | danger) default info
19102 * @cfg {String} beforeClass insert the bar before the given class
19103 * @cfg {Boolean} closable (true | false) default false
19104 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19107 * Create a new Element
19108 * @param {Object} config The config object
19111 Roo.bootstrap.MessageBar = function(config){
19112 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19115 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19121 beforeClass: 'bootstrap-sticky-wrap',
19123 getAutoCreate : function(){
19127 cls: 'alert alert-dismissable alert-' + this.weight,
19132 html: this.html || ''
19138 cfg.cls += ' alert-messages-fixed';
19152 onRender : function(ct, position)
19154 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19157 var cfg = Roo.apply({}, this.getAutoCreate());
19161 cfg.cls += ' ' + this.cls;
19164 cfg.style = this.style;
19166 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19168 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19171 this.el.select('>button.close').on('click', this.hide, this);
19177 if (!this.rendered) {
19183 this.fireEvent('show', this);
19189 if (!this.rendered) {
19195 this.fireEvent('hide', this);
19198 update : function()
19200 // var e = this.el.dom.firstChild;
19202 // if(this.closable){
19203 // e = e.nextSibling;
19206 // e.data = this.html || '';
19208 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19224 * @class Roo.bootstrap.Graph
19225 * @extends Roo.bootstrap.Component
19226 * Bootstrap Graph class
19230 @cfg {String} graphtype bar | vbar | pie
19231 @cfg {number} g_x coodinator | centre x (pie)
19232 @cfg {number} g_y coodinator | centre y (pie)
19233 @cfg {number} g_r radius (pie)
19234 @cfg {number} g_height height of the chart (respected by all elements in the set)
19235 @cfg {number} g_width width of the chart (respected by all elements in the set)
19236 @cfg {Object} title The title of the chart
19239 -opts (object) options for the chart
19241 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19242 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19244 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.
19245 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19247 o stretch (boolean)
19249 -opts (object) options for the pie
19252 o startAngle (number)
19253 o endAngle (number)
19257 * Create a new Input
19258 * @param {Object} config The config object
19261 Roo.bootstrap.Graph = function(config){
19262 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19268 * The img click event for the img.
19269 * @param {Roo.EventObject} e
19275 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19286 //g_colors: this.colors,
19293 getAutoCreate : function(){
19304 onRender : function(ct,position){
19305 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19306 this.raphael = Raphael(this.el.dom);
19308 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19309 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19310 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19311 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19313 r.text(160, 10, "Single Series Chart").attr(txtattr);
19314 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19315 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19316 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19318 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19319 r.barchart(330, 10, 300, 220, data1);
19320 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19321 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19324 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19325 // r.barchart(30, 30, 560, 250, xdata, {
19326 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19327 // axis : "0 0 1 1",
19328 // axisxlabels : xdata
19329 // //yvalues : cols,
19332 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19334 // this.load(null,xdata,{
19335 // axis : "0 0 1 1",
19336 // axisxlabels : xdata
19341 load : function(graphtype,xdata,opts){
19342 this.raphael.clear();
19344 graphtype = this.graphtype;
19349 var r = this.raphael,
19350 fin = function () {
19351 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19353 fout = function () {
19354 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19356 pfin = function() {
19357 this.sector.stop();
19358 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19361 this.label[0].stop();
19362 this.label[0].attr({ r: 7.5 });
19363 this.label[1].attr({ "font-weight": 800 });
19366 pfout = function() {
19367 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19370 this.label[0].animate({ r: 5 }, 500, "bounce");
19371 this.label[1].attr({ "font-weight": 400 });
19377 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19380 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19383 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19384 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19386 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19393 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19398 setTitle: function(o)
19403 initEvents: function() {
19406 this.el.on('click', this.onClick, this);
19410 onClick : function(e)
19412 Roo.log('img onclick');
19413 this.fireEvent('click', this, e);
19425 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19428 * @class Roo.bootstrap.dash.NumberBox
19429 * @extends Roo.bootstrap.Component
19430 * Bootstrap NumberBox class
19431 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19432 * @cfg {String} headline Box headline
19433 * @cfg {String} content Box content
19434 * @cfg {String} icon Box icon
19435 * @cfg {String} footer Footer text
19436 * @cfg {String} fhref Footer href
19439 * Create a new NumberBox
19440 * @param {Object} config The config object
19444 Roo.bootstrap.dash.NumberBox = function(config){
19445 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19449 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19459 getAutoCreate : function(){
19463 cls : 'small-box bg-' + this.bgcolor,
19471 cls : 'roo-headline',
19472 html : this.headline
19476 cls : 'roo-content',
19477 html : this.content
19491 cls : 'ion ' + this.icon
19500 cls : 'small-box-footer',
19501 href : this.fhref || '#',
19505 cfg.cn.push(footer);
19512 onRender : function(ct,position){
19513 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19520 setHeadline: function (value)
19522 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19525 setFooter: function (value, href)
19527 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19530 this.el.select('a.small-box-footer',true).first().attr('href', href);
19535 setContent: function (value)
19537 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19540 initEvents: function()
19554 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19557 * @class Roo.bootstrap.dash.TabBox
19558 * @extends Roo.bootstrap.Component
19559 * Bootstrap TabBox class
19560 * @cfg {String} title Title of the TabBox
19561 * @cfg {String} icon Icon of the TabBox
19562 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19565 * Create a new TabBox
19566 * @param {Object} config The config object
19570 Roo.bootstrap.dash.TabBox = function(config){
19571 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19576 * When a pane is added
19577 * @param {Roo.bootstrap.dash.TabPane} pane
19584 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19590 getChildContainer : function()
19592 return this.el.select('.tab-content', true).first();
19595 getAutoCreate : function(){
19599 cls: 'pull-left header',
19607 cls: 'fa ' + this.icon
19614 cls: 'nav-tabs-custom',
19618 cls: 'nav nav-tabs pull-right',
19625 cls: 'tab-content no-padding',
19633 initEvents : function()
19635 //Roo.log('add add pane handler');
19636 this.on('addpane', this.onAddPane, this);
19639 * Updates the box title
19640 * @param {String} html to set the title to.
19642 setTitle : function(value)
19644 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19646 onAddPane : function(pane)
19648 //Roo.log('addpane');
19650 // tabs are rendere left to right..
19651 if(!this.showtabs){
19655 var ctr = this.el.select('.nav-tabs', true).first();
19658 var existing = ctr.select('.nav-tab',true);
19659 var qty = existing.getCount();;
19662 var tab = ctr.createChild({
19664 cls : 'nav-tab' + (qty ? '' : ' active'),
19672 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19675 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19677 pane.el.addClass('active');
19682 onTabClick : function(ev,un,ob,pane)
19684 //Roo.log('tab - prev default');
19685 ev.preventDefault();
19688 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19689 pane.tab.addClass('active');
19690 //Roo.log(pane.title);
19691 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19692 // technically we should have a deactivate event.. but maybe add later.
19693 // and it should not de-activate the selected tab...
19695 pane.el.addClass('active');
19696 pane.fireEvent('activate');
19711 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19713 * @class Roo.bootstrap.TabPane
19714 * @extends Roo.bootstrap.Component
19715 * Bootstrap TabPane class
19716 * @cfg {Boolean} active (false | true) Default false
19717 * @cfg {String} title title of panel
19721 * Create a new TabPane
19722 * @param {Object} config The config object
19725 Roo.bootstrap.dash.TabPane = function(config){
19726 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19730 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19735 // the tabBox that this is attached to.
19738 getAutoCreate : function()
19746 cfg.cls += ' active';
19751 initEvents : function()
19753 //Roo.log('trigger add pane handler');
19754 this.parent().fireEvent('addpane', this)
19758 * Updates the tab title
19759 * @param {String} html to set the title to.
19761 setTitle: function(str)
19767 this.tab.select('a'.true).first().dom.innerHTML = str;
19784 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19787 * @class Roo.bootstrap.menu.Menu
19788 * @extends Roo.bootstrap.Component
19789 * Bootstrap Menu class - container for Menu
19790 * @cfg {String} html Text of the menu
19791 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19792 * @cfg {String} icon Font awesome icon
19793 * @cfg {String} pos Menu align to (top | bottom) default bottom
19797 * Create a new Menu
19798 * @param {Object} config The config object
19802 Roo.bootstrap.menu.Menu = function(config){
19803 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19807 * @event beforeshow
19808 * Fires before this menu is displayed
19809 * @param {Roo.bootstrap.menu.Menu} this
19813 * @event beforehide
19814 * Fires before this menu is hidden
19815 * @param {Roo.bootstrap.menu.Menu} this
19820 * Fires after this menu is displayed
19821 * @param {Roo.bootstrap.menu.Menu} this
19826 * Fires after this menu is hidden
19827 * @param {Roo.bootstrap.menu.Menu} this
19832 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19833 * @param {Roo.bootstrap.menu.Menu} this
19834 * @param {Roo.EventObject} e
19841 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19845 weight : 'default',
19850 getChildContainer : function() {
19851 if(this.isSubMenu){
19855 return this.el.select('ul.dropdown-menu', true).first();
19858 getAutoCreate : function()
19863 cls : 'roo-menu-text',
19871 cls : 'fa ' + this.icon
19882 cls : 'dropdown-button btn btn-' + this.weight,
19887 cls : 'dropdown-toggle btn btn-' + this.weight,
19897 cls : 'dropdown-menu'
19903 if(this.pos == 'top'){
19904 cfg.cls += ' dropup';
19907 if(this.isSubMenu){
19910 cls : 'dropdown-menu'
19917 onRender : function(ct, position)
19919 this.isSubMenu = ct.hasClass('dropdown-submenu');
19921 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19924 initEvents : function()
19926 if(this.isSubMenu){
19930 this.hidden = true;
19932 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19933 this.triggerEl.on('click', this.onTriggerPress, this);
19935 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19936 this.buttonEl.on('click', this.onClick, this);
19942 if(this.isSubMenu){
19946 return this.el.select('ul.dropdown-menu', true).first();
19949 onClick : function(e)
19951 this.fireEvent("click", this, e);
19954 onTriggerPress : function(e)
19956 if (this.isVisible()) {
19963 isVisible : function(){
19964 return !this.hidden;
19969 this.fireEvent("beforeshow", this);
19971 this.hidden = false;
19972 this.el.addClass('open');
19974 Roo.get(document).on("mouseup", this.onMouseUp, this);
19976 this.fireEvent("show", this);
19983 this.fireEvent("beforehide", this);
19985 this.hidden = true;
19986 this.el.removeClass('open');
19988 Roo.get(document).un("mouseup", this.onMouseUp);
19990 this.fireEvent("hide", this);
19993 onMouseUp : function()
20007 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20010 * @class Roo.bootstrap.menu.Item
20011 * @extends Roo.bootstrap.Component
20012 * Bootstrap MenuItem class
20013 * @cfg {Boolean} submenu (true | false) default false
20014 * @cfg {String} html text of the item
20015 * @cfg {String} href the link
20016 * @cfg {Boolean} disable (true | false) default false
20017 * @cfg {Boolean} preventDefault (true | false) default true
20018 * @cfg {String} icon Font awesome icon
20019 * @cfg {String} pos Submenu align to (left | right) default right
20023 * Create a new Item
20024 * @param {Object} config The config object
20028 Roo.bootstrap.menu.Item = function(config){
20029 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20033 * Fires when the mouse is hovering over this menu
20034 * @param {Roo.bootstrap.menu.Item} this
20035 * @param {Roo.EventObject} e
20040 * Fires when the mouse exits this menu
20041 * @param {Roo.bootstrap.menu.Item} this
20042 * @param {Roo.EventObject} e
20048 * The raw click event for the entire grid.
20049 * @param {Roo.EventObject} e
20055 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20060 preventDefault: true,
20065 getAutoCreate : function()
20070 cls : 'roo-menu-item-text',
20078 cls : 'fa ' + this.icon
20087 href : this.href || '#',
20094 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20098 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20100 if(this.pos == 'left'){
20101 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20108 initEvents : function()
20110 this.el.on('mouseover', this.onMouseOver, this);
20111 this.el.on('mouseout', this.onMouseOut, this);
20113 this.el.select('a', true).first().on('click', this.onClick, this);
20117 onClick : function(e)
20119 if(this.preventDefault){
20120 e.preventDefault();
20123 this.fireEvent("click", this, e);
20126 onMouseOver : function(e)
20128 if(this.submenu && this.pos == 'left'){
20129 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20132 this.fireEvent("mouseover", this, e);
20135 onMouseOut : function(e)
20137 this.fireEvent("mouseout", this, e);
20149 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20152 * @class Roo.bootstrap.menu.Separator
20153 * @extends Roo.bootstrap.Component
20154 * Bootstrap Separator class
20157 * Create a new Separator
20158 * @param {Object} config The config object
20162 Roo.bootstrap.menu.Separator = function(config){
20163 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20166 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20168 getAutoCreate : function(){