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'
7923 initTrigger : function(){
7928 onDestroy : function(){
7930 this.trigger.removeAllListeners();
7931 // this.trigger.remove();
7934 // this.wrap.remove();
7936 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7940 onFocus : function(){
7941 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7944 this.wrap.addClass('x-trigger-wrap-focus');
7945 this.mimicing = true;
7946 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7947 if(this.monitorTab){
7948 this.el.on("keydown", this.checkTab, this);
7955 checkTab : function(e){
7956 if(e.getKey() == e.TAB){
7962 onBlur : function(){
7967 mimicBlur : function(e, t){
7969 if(!this.wrap.contains(t) && this.validateBlur()){
7976 triggerBlur : function(){
7977 this.mimicing = false;
7978 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7979 if(this.monitorTab){
7980 this.el.un("keydown", this.checkTab, this);
7982 //this.wrap.removeClass('x-trigger-wrap-focus');
7983 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7987 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7988 validateBlur : function(e, t){
7993 onDisable : function(){
7994 this.inputEl().dom.disabled = true;
7995 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7997 // this.wrap.addClass('x-item-disabled');
8002 onEnable : function(){
8003 this.inputEl().dom.disabled = false;
8004 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8006 // this.el.removeClass('x-item-disabled');
8011 onShow : function(){
8012 var ae = this.getActionEl();
8015 ae.dom.style.display = '';
8016 ae.dom.style.visibility = 'visible';
8022 onHide : function(){
8023 var ae = this.getActionEl();
8024 ae.dom.style.display = 'none';
8028 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8029 * by an implementing function.
8031 * @param {EventObject} e
8033 onTriggerClick : Roo.emptyFn
8037 * Ext JS Library 1.1.1
8038 * Copyright(c) 2006-2007, Ext JS, LLC.
8040 * Originally Released Under LGPL - original licence link has changed is not relivant.
8043 * <script type="text/javascript">
8048 * @class Roo.data.SortTypes
8050 * Defines the default sorting (casting?) comparison functions used when sorting data.
8052 Roo.data.SortTypes = {
8054 * Default sort that does nothing
8055 * @param {Mixed} s The value being converted
8056 * @return {Mixed} The comparison value
8063 * The regular expression used to strip tags
8067 stripTagsRE : /<\/?[^>]+>/gi,
8070 * Strips all HTML tags to sort on text only
8071 * @param {Mixed} s The value being converted
8072 * @return {String} The comparison value
8074 asText : function(s){
8075 return String(s).replace(this.stripTagsRE, "");
8079 * Strips all HTML tags to sort on text only - Case insensitive
8080 * @param {Mixed} s The value being converted
8081 * @return {String} The comparison value
8083 asUCText : function(s){
8084 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8088 * Case insensitive string
8089 * @param {Mixed} s The value being converted
8090 * @return {String} The comparison value
8092 asUCString : function(s) {
8093 return String(s).toUpperCase();
8098 * @param {Mixed} s The value being converted
8099 * @return {Number} The comparison value
8101 asDate : function(s) {
8105 if(s instanceof Date){
8108 return Date.parse(String(s));
8113 * @param {Mixed} s The value being converted
8114 * @return {Float} The comparison value
8116 asFloat : function(s) {
8117 var val = parseFloat(String(s).replace(/,/g, ""));
8118 if(isNaN(val)) val = 0;
8124 * @param {Mixed} s The value being converted
8125 * @return {Number} The comparison value
8127 asInt : function(s) {
8128 var val = parseInt(String(s).replace(/,/g, ""));
8129 if(isNaN(val)) val = 0;
8134 * Ext JS Library 1.1.1
8135 * Copyright(c) 2006-2007, Ext JS, LLC.
8137 * Originally Released Under LGPL - original licence link has changed is not relivant.
8140 * <script type="text/javascript">
8144 * @class Roo.data.Record
8145 * Instances of this class encapsulate both record <em>definition</em> information, and record
8146 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8147 * to access Records cached in an {@link Roo.data.Store} object.<br>
8149 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8150 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8153 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8155 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8156 * {@link #create}. The parameters are the same.
8157 * @param {Array} data An associative Array of data values keyed by the field name.
8158 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8159 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8160 * not specified an integer id is generated.
8162 Roo.data.Record = function(data, id){
8163 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8168 * Generate a constructor for a specific record layout.
8169 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8170 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8171 * Each field definition object may contain the following properties: <ul>
8172 * <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,
8173 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8174 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8175 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8176 * is being used, then this is a string containing the javascript expression to reference the data relative to
8177 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8178 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8179 * this may be omitted.</p></li>
8180 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8181 * <ul><li>auto (Default, implies no conversion)</li>
8186 * <li>date</li></ul></p></li>
8187 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8188 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8189 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8190 * by the Reader into an object that will be stored in the Record. It is passed the
8191 * following parameters:<ul>
8192 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8194 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8196 * <br>usage:<br><pre><code>
8197 var TopicRecord = Roo.data.Record.create(
8198 {name: 'title', mapping: 'topic_title'},
8199 {name: 'author', mapping: 'username'},
8200 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8201 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8202 {name: 'lastPoster', mapping: 'user2'},
8203 {name: 'excerpt', mapping: 'post_text'}
8206 var myNewRecord = new TopicRecord({
8207 title: 'Do my job please',
8210 lastPost: new Date(),
8211 lastPoster: 'Animal',
8212 excerpt: 'No way dude!'
8214 myStore.add(myNewRecord);
8219 Roo.data.Record.create = function(o){
8221 f.superclass.constructor.apply(this, arguments);
8223 Roo.extend(f, Roo.data.Record);
8224 var p = f.prototype;
8225 p.fields = new Roo.util.MixedCollection(false, function(field){
8228 for(var i = 0, len = o.length; i < len; i++){
8229 p.fields.add(new Roo.data.Field(o[i]));
8231 f.getField = function(name){
8232 return p.fields.get(name);
8237 Roo.data.Record.AUTO_ID = 1000;
8238 Roo.data.Record.EDIT = 'edit';
8239 Roo.data.Record.REJECT = 'reject';
8240 Roo.data.Record.COMMIT = 'commit';
8242 Roo.data.Record.prototype = {
8244 * Readonly flag - true if this record has been modified.
8253 join : function(store){
8258 * Set the named field to the specified value.
8259 * @param {String} name The name of the field to set.
8260 * @param {Object} value The value to set the field to.
8262 set : function(name, value){
8263 if(this.data[name] == value){
8270 if(typeof this.modified[name] == 'undefined'){
8271 this.modified[name] = this.data[name];
8273 this.data[name] = value;
8274 if(!this.editing && this.store){
8275 this.store.afterEdit(this);
8280 * Get the value of the named field.
8281 * @param {String} name The name of the field to get the value of.
8282 * @return {Object} The value of the field.
8284 get : function(name){
8285 return this.data[name];
8289 beginEdit : function(){
8290 this.editing = true;
8295 cancelEdit : function(){
8296 this.editing = false;
8297 delete this.modified;
8301 endEdit : function(){
8302 this.editing = false;
8303 if(this.dirty && this.store){
8304 this.store.afterEdit(this);
8309 * Usually called by the {@link Roo.data.Store} which owns the Record.
8310 * Rejects all changes made to the Record since either creation, or the last commit operation.
8311 * Modified fields are reverted to their original values.
8313 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8314 * of reject operations.
8316 reject : function(){
8317 var m = this.modified;
8319 if(typeof m[n] != "function"){
8320 this.data[n] = m[n];
8324 delete this.modified;
8325 this.editing = false;
8327 this.store.afterReject(this);
8332 * Usually called by the {@link Roo.data.Store} which owns the Record.
8333 * Commits all changes made to the Record since either creation, or the last commit operation.
8335 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8336 * of commit operations.
8338 commit : function(){
8340 delete this.modified;
8341 this.editing = false;
8343 this.store.afterCommit(this);
8348 hasError : function(){
8349 return this.error != null;
8353 clearError : function(){
8358 * Creates a copy of this record.
8359 * @param {String} id (optional) A new record id if you don't want to use this record's id
8362 copy : function(newId) {
8363 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8367 * Ext JS Library 1.1.1
8368 * Copyright(c) 2006-2007, Ext JS, LLC.
8370 * Originally Released Under LGPL - original licence link has changed is not relivant.
8373 * <script type="text/javascript">
8379 * @class Roo.data.Store
8380 * @extends Roo.util.Observable
8381 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8382 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8384 * 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
8385 * has no knowledge of the format of the data returned by the Proxy.<br>
8387 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8388 * instances from the data object. These records are cached and made available through accessor functions.
8390 * Creates a new Store.
8391 * @param {Object} config A config object containing the objects needed for the Store to access data,
8392 * and read the data into Records.
8394 Roo.data.Store = function(config){
8395 this.data = new Roo.util.MixedCollection(false);
8396 this.data.getKey = function(o){
8399 this.baseParams = {};
8406 "multisort" : "_multisort"
8409 if(config && config.data){
8410 this.inlineData = config.data;
8414 Roo.apply(this, config);
8416 if(this.reader){ // reader passed
8417 this.reader = Roo.factory(this.reader, Roo.data);
8418 this.reader.xmodule = this.xmodule || false;
8419 if(!this.recordType){
8420 this.recordType = this.reader.recordType;
8422 if(this.reader.onMetaChange){
8423 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8427 if(this.recordType){
8428 this.fields = this.recordType.prototype.fields;
8434 * @event datachanged
8435 * Fires when the data cache has changed, and a widget which is using this Store
8436 * as a Record cache should refresh its view.
8437 * @param {Store} this
8442 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8443 * @param {Store} this
8444 * @param {Object} meta The JSON metadata
8449 * Fires when Records have been added to the Store
8450 * @param {Store} this
8451 * @param {Roo.data.Record[]} records The array of Records added
8452 * @param {Number} index The index at which the record(s) were added
8457 * Fires when a Record has been removed from the Store
8458 * @param {Store} this
8459 * @param {Roo.data.Record} record The Record that was removed
8460 * @param {Number} index The index at which the record was removed
8465 * Fires when a Record has been updated
8466 * @param {Store} this
8467 * @param {Roo.data.Record} record The Record that was updated
8468 * @param {String} operation The update operation being performed. Value may be one of:
8470 Roo.data.Record.EDIT
8471 Roo.data.Record.REJECT
8472 Roo.data.Record.COMMIT
8478 * Fires when the data cache has been cleared.
8479 * @param {Store} this
8484 * Fires before a request is made for a new data object. If the beforeload handler returns false
8485 * the load action will be canceled.
8486 * @param {Store} this
8487 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8491 * @event beforeloadadd
8492 * Fires after a new set of Records has been loaded.
8493 * @param {Store} this
8494 * @param {Roo.data.Record[]} records The Records that were loaded
8495 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8497 beforeloadadd : true,
8500 * Fires after a new set of Records has been loaded, before they are added to the store.
8501 * @param {Store} this
8502 * @param {Roo.data.Record[]} records The Records that were loaded
8503 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8504 * @params {Object} return from reader
8508 * @event loadexception
8509 * Fires if an exception occurs in the Proxy during loading.
8510 * Called with the signature of the Proxy's "loadexception" event.
8511 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8514 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8515 * @param {Object} load options
8516 * @param {Object} jsonData from your request (normally this contains the Exception)
8518 loadexception : true
8522 this.proxy = Roo.factory(this.proxy, Roo.data);
8523 this.proxy.xmodule = this.xmodule || false;
8524 this.relayEvents(this.proxy, ["loadexception"]);
8526 this.sortToggle = {};
8527 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8529 Roo.data.Store.superclass.constructor.call(this);
8531 if(this.inlineData){
8532 this.loadData(this.inlineData);
8533 delete this.inlineData;
8537 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8539 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8540 * without a remote query - used by combo/forms at present.
8544 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8547 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8550 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8551 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8554 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8555 * on any HTTP request
8558 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8561 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8565 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8566 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8571 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8572 * loaded or when a record is removed. (defaults to false).
8574 pruneModifiedRecords : false,
8580 * Add Records to the Store and fires the add event.
8581 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8583 add : function(records){
8584 records = [].concat(records);
8585 for(var i = 0, len = records.length; i < len; i++){
8586 records[i].join(this);
8588 var index = this.data.length;
8589 this.data.addAll(records);
8590 this.fireEvent("add", this, records, index);
8594 * Remove a Record from the Store and fires the remove event.
8595 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8597 remove : function(record){
8598 var index = this.data.indexOf(record);
8599 this.data.removeAt(index);
8600 if(this.pruneModifiedRecords){
8601 this.modified.remove(record);
8603 this.fireEvent("remove", this, record, index);
8607 * Remove all Records from the Store and fires the clear event.
8609 removeAll : function(){
8611 if(this.pruneModifiedRecords){
8614 this.fireEvent("clear", this);
8618 * Inserts Records to the Store at the given index and fires the add event.
8619 * @param {Number} index The start index at which to insert the passed Records.
8620 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8622 insert : function(index, records){
8623 records = [].concat(records);
8624 for(var i = 0, len = records.length; i < len; i++){
8625 this.data.insert(index, records[i]);
8626 records[i].join(this);
8628 this.fireEvent("add", this, records, index);
8632 * Get the index within the cache of the passed Record.
8633 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8634 * @return {Number} The index of the passed Record. Returns -1 if not found.
8636 indexOf : function(record){
8637 return this.data.indexOf(record);
8641 * Get the index within the cache of the Record with the passed id.
8642 * @param {String} id The id of the Record to find.
8643 * @return {Number} The index of the Record. Returns -1 if not found.
8645 indexOfId : function(id){
8646 return this.data.indexOfKey(id);
8650 * Get the Record with the specified id.
8651 * @param {String} id The id of the Record to find.
8652 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8654 getById : function(id){
8655 return this.data.key(id);
8659 * Get the Record at the specified index.
8660 * @param {Number} index The index of the Record to find.
8661 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8663 getAt : function(index){
8664 return this.data.itemAt(index);
8668 * Returns a range of Records between specified indices.
8669 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8670 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8671 * @return {Roo.data.Record[]} An array of Records
8673 getRange : function(start, end){
8674 return this.data.getRange(start, end);
8678 storeOptions : function(o){
8679 o = Roo.apply({}, o);
8682 this.lastOptions = o;
8686 * Loads the Record cache from the configured Proxy using the configured Reader.
8688 * If using remote paging, then the first load call must specify the <em>start</em>
8689 * and <em>limit</em> properties in the options.params property to establish the initial
8690 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8692 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8693 * and this call will return before the new data has been loaded. Perform any post-processing
8694 * in a callback function, or in a "load" event handler.</strong>
8696 * @param {Object} options An object containing properties which control loading options:<ul>
8697 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8698 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8699 * passed the following arguments:<ul>
8700 * <li>r : Roo.data.Record[]</li>
8701 * <li>options: Options object from the load call</li>
8702 * <li>success: Boolean success indicator</li></ul></li>
8703 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8704 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8707 load : function(options){
8708 options = options || {};
8709 if(this.fireEvent("beforeload", this, options) !== false){
8710 this.storeOptions(options);
8711 var p = Roo.apply(options.params || {}, this.baseParams);
8712 // if meta was not loaded from remote source.. try requesting it.
8713 if (!this.reader.metaFromRemote) {
8716 if(this.sortInfo && this.remoteSort){
8717 var pn = this.paramNames;
8718 p[pn["sort"]] = this.sortInfo.field;
8719 p[pn["dir"]] = this.sortInfo.direction;
8721 if (this.multiSort) {
8722 var pn = this.paramNames;
8723 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8726 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8731 * Reloads the Record cache from the configured Proxy using the configured Reader and
8732 * the options from the last load operation performed.
8733 * @param {Object} options (optional) An object containing properties which may override the options
8734 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8735 * the most recently used options are reused).
8737 reload : function(options){
8738 this.load(Roo.applyIf(options||{}, this.lastOptions));
8742 // Called as a callback by the Reader during a load operation.
8743 loadRecords : function(o, options, success){
8744 if(!o || success === false){
8745 if(success !== false){
8746 this.fireEvent("load", this, [], options, o);
8748 if(options.callback){
8749 options.callback.call(options.scope || this, [], options, false);
8753 // if data returned failure - throw an exception.
8754 if (o.success === false) {
8755 // show a message if no listener is registered.
8756 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8757 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8759 // loadmask wil be hooked into this..
8760 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8763 var r = o.records, t = o.totalRecords || r.length;
8765 this.fireEvent("beforeloadadd", this, r, options, o);
8767 if(!options || options.add !== true){
8768 if(this.pruneModifiedRecords){
8771 for(var i = 0, len = r.length; i < len; i++){
8775 this.data = this.snapshot;
8776 delete this.snapshot;
8779 this.data.addAll(r);
8780 this.totalLength = t;
8782 this.fireEvent("datachanged", this);
8784 this.totalLength = Math.max(t, this.data.length+r.length);
8787 this.fireEvent("load", this, r, options, o);
8788 if(options.callback){
8789 options.callback.call(options.scope || this, r, options, true);
8795 * Loads data from a passed data block. A Reader which understands the format of the data
8796 * must have been configured in the constructor.
8797 * @param {Object} data The data block from which to read the Records. The format of the data expected
8798 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8799 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8801 loadData : function(o, append){
8802 var r = this.reader.readRecords(o);
8803 this.loadRecords(r, {add: append}, true);
8807 * Gets the number of cached records.
8809 * <em>If using paging, this may not be the total size of the dataset. If the data object
8810 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8811 * the data set size</em>
8813 getCount : function(){
8814 return this.data.length || 0;
8818 * Gets the total number of records in the dataset as returned by the server.
8820 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8821 * the dataset size</em>
8823 getTotalCount : function(){
8824 return this.totalLength || 0;
8828 * Returns the sort state of the Store as an object with two properties:
8830 field {String} The name of the field by which the Records are sorted
8831 direction {String} The sort order, "ASC" or "DESC"
8834 getSortState : function(){
8835 return this.sortInfo;
8839 applySort : function(){
8840 if(this.sortInfo && !this.remoteSort){
8841 var s = this.sortInfo, f = s.field;
8842 var st = this.fields.get(f).sortType;
8843 var fn = function(r1, r2){
8844 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8845 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8847 this.data.sort(s.direction, fn);
8848 if(this.snapshot && this.snapshot != this.data){
8849 this.snapshot.sort(s.direction, fn);
8855 * Sets the default sort column and order to be used by the next load operation.
8856 * @param {String} fieldName The name of the field to sort by.
8857 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8859 setDefaultSort : function(field, dir){
8860 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8865 * If remote sorting is used, the sort is performed on the server, and the cache is
8866 * reloaded. If local sorting is used, the cache is sorted internally.
8867 * @param {String} fieldName The name of the field to sort by.
8868 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8870 sort : function(fieldName, dir){
8871 var f = this.fields.get(fieldName);
8873 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8875 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8876 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8881 this.sortToggle[f.name] = dir;
8882 this.sortInfo = {field: f.name, direction: dir};
8883 if(!this.remoteSort){
8885 this.fireEvent("datachanged", this);
8887 this.load(this.lastOptions);
8892 * Calls the specified function for each of the Records in the cache.
8893 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8894 * Returning <em>false</em> aborts and exits the iteration.
8895 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8897 each : function(fn, scope){
8898 this.data.each(fn, scope);
8902 * Gets all records modified since the last commit. Modified records are persisted across load operations
8903 * (e.g., during paging).
8904 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8906 getModifiedRecords : function(){
8907 return this.modified;
8911 createFilterFn : function(property, value, anyMatch){
8912 if(!value.exec){ // not a regex
8913 value = String(value);
8914 if(value.length == 0){
8917 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8920 return value.test(r.data[property]);
8925 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8926 * @param {String} property A field on your records
8927 * @param {Number} start The record index to start at (defaults to 0)
8928 * @param {Number} end The last record index to include (defaults to length - 1)
8929 * @return {Number} The sum
8931 sum : function(property, start, end){
8932 var rs = this.data.items, v = 0;
8934 end = (end || end === 0) ? end : rs.length-1;
8936 for(var i = start; i <= end; i++){
8937 v += (rs[i].data[property] || 0);
8943 * Filter the records by a specified property.
8944 * @param {String} field A field on your records
8945 * @param {String/RegExp} value Either a string that the field
8946 * should start with or a RegExp to test against the field
8947 * @param {Boolean} anyMatch True to match any part not just the beginning
8949 filter : function(property, value, anyMatch){
8950 var fn = this.createFilterFn(property, value, anyMatch);
8951 return fn ? this.filterBy(fn) : this.clearFilter();
8955 * Filter by a function. The specified function will be called with each
8956 * record in this data source. If the function returns true the record is included,
8957 * otherwise it is filtered.
8958 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8959 * @param {Object} scope (optional) The scope of the function (defaults to this)
8961 filterBy : function(fn, scope){
8962 this.snapshot = this.snapshot || this.data;
8963 this.data = this.queryBy(fn, scope||this);
8964 this.fireEvent("datachanged", this);
8968 * Query the records by a specified property.
8969 * @param {String} field A field on your records
8970 * @param {String/RegExp} value Either a string that the field
8971 * should start with or a RegExp to test against the field
8972 * @param {Boolean} anyMatch True to match any part not just the beginning
8973 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8975 query : function(property, value, anyMatch){
8976 var fn = this.createFilterFn(property, value, anyMatch);
8977 return fn ? this.queryBy(fn) : this.data.clone();
8981 * Query by a function. The specified function will be called with each
8982 * record in this data source. If the function returns true the record is included
8984 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8985 * @param {Object} scope (optional) The scope of the function (defaults to this)
8986 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8988 queryBy : function(fn, scope){
8989 var data = this.snapshot || this.data;
8990 return data.filterBy(fn, scope||this);
8994 * Collects unique values for a particular dataIndex from this store.
8995 * @param {String} dataIndex The property to collect
8996 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8997 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8998 * @return {Array} An array of the unique values
9000 collect : function(dataIndex, allowNull, bypassFilter){
9001 var d = (bypassFilter === true && this.snapshot) ?
9002 this.snapshot.items : this.data.items;
9003 var v, sv, r = [], l = {};
9004 for(var i = 0, len = d.length; i < len; i++){
9005 v = d[i].data[dataIndex];
9007 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9016 * Revert to a view of the Record cache with no filtering applied.
9017 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9019 clearFilter : function(suppressEvent){
9020 if(this.snapshot && this.snapshot != this.data){
9021 this.data = this.snapshot;
9022 delete this.snapshot;
9023 if(suppressEvent !== true){
9024 this.fireEvent("datachanged", this);
9030 afterEdit : function(record){
9031 if(this.modified.indexOf(record) == -1){
9032 this.modified.push(record);
9034 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9038 afterReject : function(record){
9039 this.modified.remove(record);
9040 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9044 afterCommit : function(record){
9045 this.modified.remove(record);
9046 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9050 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9051 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9053 commitChanges : function(){
9054 var m = this.modified.slice(0);
9056 for(var i = 0, len = m.length; i < len; i++){
9062 * Cancel outstanding changes on all changed records.
9064 rejectChanges : function(){
9065 var m = this.modified.slice(0);
9067 for(var i = 0, len = m.length; i < len; i++){
9072 onMetaChange : function(meta, rtype, o){
9073 this.recordType = rtype;
9074 this.fields = rtype.prototype.fields;
9075 delete this.snapshot;
9076 this.sortInfo = meta.sortInfo || this.sortInfo;
9078 this.fireEvent('metachange', this, this.reader.meta);
9081 moveIndex : function(data, type)
9083 var index = this.indexOf(data);
9085 var newIndex = index + type;
9089 this.insert(newIndex, data);
9094 * Ext JS Library 1.1.1
9095 * Copyright(c) 2006-2007, Ext JS, LLC.
9097 * Originally Released Under LGPL - original licence link has changed is not relivant.
9100 * <script type="text/javascript">
9104 * @class Roo.data.SimpleStore
9105 * @extends Roo.data.Store
9106 * Small helper class to make creating Stores from Array data easier.
9107 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9108 * @cfg {Array} fields An array of field definition objects, or field name strings.
9109 * @cfg {Array} data The multi-dimensional array of data
9111 * @param {Object} config
9113 Roo.data.SimpleStore = function(config){
9114 Roo.data.SimpleStore.superclass.constructor.call(this, {
9116 reader: new Roo.data.ArrayReader({
9119 Roo.data.Record.create(config.fields)
9121 proxy : new Roo.data.MemoryProxy(config.data)
9125 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9127 * Ext JS Library 1.1.1
9128 * Copyright(c) 2006-2007, Ext JS, LLC.
9130 * Originally Released Under LGPL - original licence link has changed is not relivant.
9133 * <script type="text/javascript">
9138 * @extends Roo.data.Store
9139 * @class Roo.data.JsonStore
9140 * Small helper class to make creating Stores for JSON data easier. <br/>
9142 var store = new Roo.data.JsonStore({
9143 url: 'get-images.php',
9145 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9148 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9149 * JsonReader and HttpProxy (unless inline data is provided).</b>
9150 * @cfg {Array} fields An array of field definition objects, or field name strings.
9152 * @param {Object} config
9154 Roo.data.JsonStore = function(c){
9155 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9156 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9157 reader: new Roo.data.JsonReader(c, c.fields)
9160 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9162 * Ext JS Library 1.1.1
9163 * Copyright(c) 2006-2007, Ext JS, LLC.
9165 * Originally Released Under LGPL - original licence link has changed is not relivant.
9168 * <script type="text/javascript">
9172 Roo.data.Field = function(config){
9173 if(typeof config == "string"){
9174 config = {name: config};
9176 Roo.apply(this, config);
9182 var st = Roo.data.SortTypes;
9183 // named sortTypes are supported, here we look them up
9184 if(typeof this.sortType == "string"){
9185 this.sortType = st[this.sortType];
9188 // set default sortType for strings and dates
9192 this.sortType = st.asUCString;
9195 this.sortType = st.asDate;
9198 this.sortType = st.none;
9203 var stripRe = /[\$,%]/g;
9205 // prebuilt conversion function for this field, instead of
9206 // switching every time we're reading a value
9208 var cv, dateFormat = this.dateFormat;
9213 cv = function(v){ return v; };
9216 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9220 return v !== undefined && v !== null && v !== '' ?
9221 parseInt(String(v).replace(stripRe, ""), 10) : '';
9226 return v !== undefined && v !== null && v !== '' ?
9227 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9232 cv = function(v){ return v === true || v === "true" || v == 1; };
9239 if(v instanceof Date){
9243 if(dateFormat == "timestamp"){
9244 return new Date(v*1000);
9246 return Date.parseDate(v, dateFormat);
9248 var parsed = Date.parse(v);
9249 return parsed ? new Date(parsed) : null;
9258 Roo.data.Field.prototype = {
9266 * Ext JS Library 1.1.1
9267 * Copyright(c) 2006-2007, Ext JS, LLC.
9269 * Originally Released Under LGPL - original licence link has changed is not relivant.
9272 * <script type="text/javascript">
9275 // Base class for reading structured data from a data source. This class is intended to be
9276 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9279 * @class Roo.data.DataReader
9280 * Base class for reading structured data from a data source. This class is intended to be
9281 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9284 Roo.data.DataReader = function(meta, recordType){
9288 this.recordType = recordType instanceof Array ?
9289 Roo.data.Record.create(recordType) : recordType;
9292 Roo.data.DataReader.prototype = {
9294 * Create an empty record
9295 * @param {Object} data (optional) - overlay some values
9296 * @return {Roo.data.Record} record created.
9298 newRow : function(d) {
9300 this.recordType.prototype.fields.each(function(c) {
9302 case 'int' : da[c.name] = 0; break;
9303 case 'date' : da[c.name] = new Date(); break;
9304 case 'float' : da[c.name] = 0.0; break;
9305 case 'boolean' : da[c.name] = false; break;
9306 default : da[c.name] = ""; break;
9310 return new this.recordType(Roo.apply(da, d));
9315 * Ext JS Library 1.1.1
9316 * Copyright(c) 2006-2007, Ext JS, LLC.
9318 * Originally Released Under LGPL - original licence link has changed is not relivant.
9321 * <script type="text/javascript">
9325 * @class Roo.data.DataProxy
9326 * @extends Roo.data.Observable
9327 * This class is an abstract base class for implementations which provide retrieval of
9328 * unformatted data objects.<br>
9330 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9331 * (of the appropriate type which knows how to parse the data object) to provide a block of
9332 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9334 * Custom implementations must implement the load method as described in
9335 * {@link Roo.data.HttpProxy#load}.
9337 Roo.data.DataProxy = function(){
9341 * Fires before a network request is made to retrieve a data object.
9342 * @param {Object} This DataProxy object.
9343 * @param {Object} params The params parameter to the load function.
9348 * Fires before the load method's callback is called.
9349 * @param {Object} This DataProxy object.
9350 * @param {Object} o The data object.
9351 * @param {Object} arg The callback argument object passed to the load function.
9355 * @event loadexception
9356 * Fires if an Exception occurs during data retrieval.
9357 * @param {Object} This DataProxy object.
9358 * @param {Object} o The data object.
9359 * @param {Object} arg The callback argument object passed to the load function.
9360 * @param {Object} e The Exception.
9362 loadexception : true
9364 Roo.data.DataProxy.superclass.constructor.call(this);
9367 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9370 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9374 * Ext JS Library 1.1.1
9375 * Copyright(c) 2006-2007, Ext JS, LLC.
9377 * Originally Released Under LGPL - original licence link has changed is not relivant.
9380 * <script type="text/javascript">
9383 * @class Roo.data.MemoryProxy
9384 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9385 * to the Reader when its load method is called.
9387 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9389 Roo.data.MemoryProxy = function(data){
9393 Roo.data.MemoryProxy.superclass.constructor.call(this);
9397 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9399 * Load data from the requested source (in this case an in-memory
9400 * data object passed to the constructor), read the data object into
9401 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9402 * process that block using the passed callback.
9403 * @param {Object} params This parameter is not used by the MemoryProxy class.
9404 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9405 * object into a block of Roo.data.Records.
9406 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9407 * The function must be passed <ul>
9408 * <li>The Record block object</li>
9409 * <li>The "arg" argument from the load function</li>
9410 * <li>A boolean success indicator</li>
9412 * @param {Object} scope The scope in which to call the callback
9413 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9415 load : function(params, reader, callback, scope, arg){
9416 params = params || {};
9419 result = reader.readRecords(this.data);
9421 this.fireEvent("loadexception", this, arg, null, e);
9422 callback.call(scope, null, arg, false);
9425 callback.call(scope, result, arg, true);
9429 update : function(params, records){
9434 * Ext JS Library 1.1.1
9435 * Copyright(c) 2006-2007, Ext JS, LLC.
9437 * Originally Released Under LGPL - original licence link has changed is not relivant.
9440 * <script type="text/javascript">
9443 * @class Roo.data.HttpProxy
9444 * @extends Roo.data.DataProxy
9445 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9446 * configured to reference a certain URL.<br><br>
9448 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9449 * from which the running page was served.<br><br>
9451 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9453 * Be aware that to enable the browser to parse an XML document, the server must set
9454 * the Content-Type header in the HTTP response to "text/xml".
9456 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9457 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9458 * will be used to make the request.
9460 Roo.data.HttpProxy = function(conn){
9461 Roo.data.HttpProxy.superclass.constructor.call(this);
9462 // is conn a conn config or a real conn?
9464 this.useAjax = !conn || !conn.events;
9468 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9469 // thse are take from connection...
9472 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9475 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9476 * extra parameters to each request made by this object. (defaults to undefined)
9479 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9480 * to each request made by this object. (defaults to undefined)
9483 * @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)
9486 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9489 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9495 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9499 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9500 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9501 * a finer-grained basis than the DataProxy events.
9503 getConnection : function(){
9504 return this.useAjax ? Roo.Ajax : this.conn;
9508 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9509 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9510 * process that block using the passed callback.
9511 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9512 * for the request to the remote server.
9513 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9514 * object into a block of Roo.data.Records.
9515 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9516 * The function must be passed <ul>
9517 * <li>The Record block object</li>
9518 * <li>The "arg" argument from the load function</li>
9519 * <li>A boolean success indicator</li>
9521 * @param {Object} scope The scope in which to call the callback
9522 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9524 load : function(params, reader, callback, scope, arg){
9525 if(this.fireEvent("beforeload", this, params) !== false){
9527 params : params || {},
9529 callback : callback,
9534 callback : this.loadResponse,
9538 Roo.applyIf(o, this.conn);
9539 if(this.activeRequest){
9540 Roo.Ajax.abort(this.activeRequest);
9542 this.activeRequest = Roo.Ajax.request(o);
9544 this.conn.request(o);
9547 callback.call(scope||this, null, arg, false);
9552 loadResponse : function(o, success, response){
9553 delete this.activeRequest;
9555 this.fireEvent("loadexception", this, o, response);
9556 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9561 result = o.reader.read(response);
9563 this.fireEvent("loadexception", this, o, response, e);
9564 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9568 this.fireEvent("load", this, o, o.request.arg);
9569 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9573 update : function(dataSet){
9578 updateResponse : function(dataSet){
9583 * Ext JS Library 1.1.1
9584 * Copyright(c) 2006-2007, Ext JS, LLC.
9586 * Originally Released Under LGPL - original licence link has changed is not relivant.
9589 * <script type="text/javascript">
9593 * @class Roo.data.ScriptTagProxy
9594 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9595 * other than the originating domain of the running page.<br><br>
9597 * <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
9598 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9600 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9601 * source code that is used as the source inside a <script> tag.<br><br>
9603 * In order for the browser to process the returned data, the server must wrap the data object
9604 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9605 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9606 * depending on whether the callback name was passed:
9609 boolean scriptTag = false;
9610 String cb = request.getParameter("callback");
9613 response.setContentType("text/javascript");
9615 response.setContentType("application/x-json");
9617 Writer out = response.getWriter();
9619 out.write(cb + "(");
9621 out.print(dataBlock.toJsonString());
9628 * @param {Object} config A configuration object.
9630 Roo.data.ScriptTagProxy = function(config){
9631 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9632 Roo.apply(this, config);
9633 this.head = document.getElementsByTagName("head")[0];
9636 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9638 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9640 * @cfg {String} url The URL from which to request the data object.
9643 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9647 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9648 * the server the name of the callback function set up by the load call to process the returned data object.
9649 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9650 * javascript output which calls this named function passing the data object as its only parameter.
9652 callbackParam : "callback",
9654 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9655 * name to the request.
9660 * Load data from the configured URL, read the data object into
9661 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9662 * process that block using the passed callback.
9663 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9664 * for the request to the remote server.
9665 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9666 * object into a block of Roo.data.Records.
9667 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9668 * The function must be passed <ul>
9669 * <li>The Record block object</li>
9670 * <li>The "arg" argument from the load function</li>
9671 * <li>A boolean success indicator</li>
9673 * @param {Object} scope The scope in which to call the callback
9674 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9676 load : function(params, reader, callback, scope, arg){
9677 if(this.fireEvent("beforeload", this, params) !== false){
9679 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9682 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9684 url += "&_dc=" + (new Date().getTime());
9686 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9689 cb : "stcCallback"+transId,
9690 scriptId : "stcScript"+transId,
9694 callback : callback,
9700 window[trans.cb] = function(o){
9701 conn.handleResponse(o, trans);
9704 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9706 if(this.autoAbort !== false){
9710 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9712 var script = document.createElement("script");
9713 script.setAttribute("src", url);
9714 script.setAttribute("type", "text/javascript");
9715 script.setAttribute("id", trans.scriptId);
9716 this.head.appendChild(script);
9720 callback.call(scope||this, null, arg, false);
9725 isLoading : function(){
9726 return this.trans ? true : false;
9730 * Abort the current server request.
9733 if(this.isLoading()){
9734 this.destroyTrans(this.trans);
9739 destroyTrans : function(trans, isLoaded){
9740 this.head.removeChild(document.getElementById(trans.scriptId));
9741 clearTimeout(trans.timeoutId);
9743 window[trans.cb] = undefined;
9745 delete window[trans.cb];
9748 // if hasn't been loaded, wait for load to remove it to prevent script error
9749 window[trans.cb] = function(){
9750 window[trans.cb] = undefined;
9752 delete window[trans.cb];
9759 handleResponse : function(o, trans){
9761 this.destroyTrans(trans, true);
9764 result = trans.reader.readRecords(o);
9766 this.fireEvent("loadexception", this, o, trans.arg, e);
9767 trans.callback.call(trans.scope||window, null, trans.arg, false);
9770 this.fireEvent("load", this, o, trans.arg);
9771 trans.callback.call(trans.scope||window, result, trans.arg, true);
9775 handleFailure : function(trans){
9777 this.destroyTrans(trans, false);
9778 this.fireEvent("loadexception", this, null, trans.arg);
9779 trans.callback.call(trans.scope||window, null, trans.arg, false);
9783 * Ext JS Library 1.1.1
9784 * Copyright(c) 2006-2007, Ext JS, LLC.
9786 * Originally Released Under LGPL - original licence link has changed is not relivant.
9789 * <script type="text/javascript">
9793 * @class Roo.data.JsonReader
9794 * @extends Roo.data.DataReader
9795 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9796 * based on mappings in a provided Roo.data.Record constructor.
9798 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9799 * in the reply previously.
9804 var RecordDef = Roo.data.Record.create([
9805 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9806 {name: 'occupation'} // This field will use "occupation" as the mapping.
9808 var myReader = new Roo.data.JsonReader({
9809 totalProperty: "results", // The property which contains the total dataset size (optional)
9810 root: "rows", // The property which contains an Array of row objects
9811 id: "id" // The property within each row object that provides an ID for the record (optional)
9815 * This would consume a JSON file like this:
9817 { 'results': 2, 'rows': [
9818 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9819 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9822 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9823 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9824 * paged from the remote server.
9825 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9826 * @cfg {String} root name of the property which contains the Array of row objects.
9827 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9829 * Create a new JsonReader
9830 * @param {Object} meta Metadata configuration options
9831 * @param {Object} recordType Either an Array of field definition objects,
9832 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9834 Roo.data.JsonReader = function(meta, recordType){
9837 // set some defaults:
9839 totalProperty: 'total',
9840 successProperty : 'success',
9845 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9847 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9850 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9851 * Used by Store query builder to append _requestMeta to params.
9854 metaFromRemote : false,
9856 * This method is only used by a DataProxy which has retrieved data from a remote server.
9857 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9858 * @return {Object} data A data block which is used by an Roo.data.Store object as
9859 * a cache of Roo.data.Records.
9861 read : function(response){
9862 var json = response.responseText;
9864 var o = /* eval:var:o */ eval("("+json+")");
9866 throw {message: "JsonReader.read: Json object not found"};
9872 this.metaFromRemote = true;
9873 this.meta = o.metaData;
9874 this.recordType = Roo.data.Record.create(o.metaData.fields);
9875 this.onMetaChange(this.meta, this.recordType, o);
9877 return this.readRecords(o);
9880 // private function a store will implement
9881 onMetaChange : function(meta, recordType, o){
9888 simpleAccess: function(obj, subsc) {
9895 getJsonAccessor: function(){
9897 return function(expr) {
9899 return(re.test(expr))
9900 ? new Function("obj", "return obj." + expr)
9910 * Create a data block containing Roo.data.Records from an XML document.
9911 * @param {Object} o An object which contains an Array of row objects in the property specified
9912 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9913 * which contains the total size of the dataset.
9914 * @return {Object} data A data block which is used by an Roo.data.Store object as
9915 * a cache of Roo.data.Records.
9917 readRecords : function(o){
9919 * After any data loads, the raw JSON data is available for further custom processing.
9923 var s = this.meta, Record = this.recordType,
9924 f = Record.prototype.fields, fi = f.items, fl = f.length;
9926 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9928 if(s.totalProperty) {
9929 this.getTotal = this.getJsonAccessor(s.totalProperty);
9931 if(s.successProperty) {
9932 this.getSuccess = this.getJsonAccessor(s.successProperty);
9934 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9936 var g = this.getJsonAccessor(s.id);
9937 this.getId = function(rec) {
9939 return (r === undefined || r === "") ? null : r;
9942 this.getId = function(){return null;};
9945 for(var jj = 0; jj < fl; jj++){
9947 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9948 this.ef[jj] = this.getJsonAccessor(map);
9952 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9953 if(s.totalProperty){
9954 var vt = parseInt(this.getTotal(o), 10);
9959 if(s.successProperty){
9960 var vs = this.getSuccess(o);
9961 if(vs === false || vs === 'false'){
9966 for(var i = 0; i < c; i++){
9969 var id = this.getId(n);
9970 for(var j = 0; j < fl; j++){
9972 var v = this.ef[j](n);
9974 Roo.log('missing convert for ' + f.name);
9978 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9980 var record = new Record(values, id);
9982 records[i] = record;
9988 totalRecords : totalRecords
9993 * Ext JS Library 1.1.1
9994 * Copyright(c) 2006-2007, Ext JS, LLC.
9996 * Originally Released Under LGPL - original licence link has changed is not relivant.
9999 * <script type="text/javascript">
10003 * @class Roo.data.ArrayReader
10004 * @extends Roo.data.DataReader
10005 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10006 * Each element of that Array represents a row of data fields. The
10007 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10008 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10012 var RecordDef = Roo.data.Record.create([
10013 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10014 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10016 var myReader = new Roo.data.ArrayReader({
10017 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10021 * This would consume an Array like this:
10023 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10025 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10027 * Create a new JsonReader
10028 * @param {Object} meta Metadata configuration options.
10029 * @param {Object} recordType Either an Array of field definition objects
10030 * as specified to {@link Roo.data.Record#create},
10031 * or an {@link Roo.data.Record} object
10032 * created using {@link Roo.data.Record#create}.
10034 Roo.data.ArrayReader = function(meta, recordType){
10035 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10038 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10040 * Create a data block containing Roo.data.Records from an XML document.
10041 * @param {Object} o An Array of row objects which represents the dataset.
10042 * @return {Object} data A data block which is used by an Roo.data.Store object as
10043 * a cache of Roo.data.Records.
10045 readRecords : function(o){
10046 var sid = this.meta ? this.meta.id : null;
10047 var recordType = this.recordType, fields = recordType.prototype.fields;
10050 for(var i = 0; i < root.length; i++){
10053 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10054 for(var j = 0, jlen = fields.length; j < jlen; j++){
10055 var f = fields.items[j];
10056 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10057 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10059 values[f.name] = v;
10061 var record = new recordType(values, id);
10063 records[records.length] = record;
10067 totalRecords : records.length
10076 * @class Roo.bootstrap.ComboBox
10077 * @extends Roo.bootstrap.TriggerField
10078 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10079 * @cfg {Boolean} append (true|false) default false
10080 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10081 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10082 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10083 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10085 * Create a new ComboBox.
10086 * @param {Object} config Configuration options
10088 Roo.bootstrap.ComboBox = function(config){
10089 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10093 * Fires when the dropdown list is expanded
10094 * @param {Roo.bootstrap.ComboBox} combo This combo box
10099 * Fires when the dropdown list is collapsed
10100 * @param {Roo.bootstrap.ComboBox} combo This combo box
10104 * @event beforeselect
10105 * Fires before a list item is selected. Return false to cancel the selection.
10106 * @param {Roo.bootstrap.ComboBox} combo This combo box
10107 * @param {Roo.data.Record} record The data record returned from the underlying store
10108 * @param {Number} index The index of the selected item in the dropdown list
10110 'beforeselect' : true,
10113 * Fires when a list item is selected
10114 * @param {Roo.bootstrap.ComboBox} combo This combo box
10115 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10116 * @param {Number} index The index of the selected item in the dropdown list
10120 * @event beforequery
10121 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10122 * The event object passed has these properties:
10123 * @param {Roo.bootstrap.ComboBox} combo This combo box
10124 * @param {String} query The query
10125 * @param {Boolean} forceAll true to force "all" query
10126 * @param {Boolean} cancel true to cancel the query
10127 * @param {Object} e The query event object
10129 'beforequery': true,
10132 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10133 * @param {Roo.bootstrap.ComboBox} combo This combo box
10138 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10139 * @param {Roo.bootstrap.ComboBox} combo This combo box
10140 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10145 * Fires when the remove value from the combobox array
10146 * @param {Roo.bootstrap.ComboBox} combo This combo box
10153 this.tickItems = [];
10155 this.selectedIndex = -1;
10156 if(this.mode == 'local'){
10157 if(config.queryDelay === undefined){
10158 this.queryDelay = 10;
10160 if(config.minChars === undefined){
10166 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10169 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10170 * rendering into an Roo.Editor, defaults to false)
10173 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10174 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10177 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10180 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10181 * the dropdown list (defaults to undefined, with no header element)
10185 * @cfg {String/Roo.Template} tpl The template to use to render the output
10189 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10191 listWidth: undefined,
10193 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10194 * mode = 'remote' or 'text' if mode = 'local')
10196 displayField: undefined,
10198 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10199 * mode = 'remote' or 'value' if mode = 'local').
10200 * Note: use of a valueField requires the user make a selection
10201 * in order for a value to be mapped.
10203 valueField: undefined,
10207 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10208 * field's data value (defaults to the underlying DOM element's name)
10210 hiddenName: undefined,
10212 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10216 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10218 selectedClass: 'active',
10221 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10225 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10226 * anchor positions (defaults to 'tl-bl')
10228 listAlign: 'tl-bl?',
10230 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10234 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10235 * query specified by the allQuery config option (defaults to 'query')
10237 triggerAction: 'query',
10239 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10240 * (defaults to 4, does not apply if editable = false)
10244 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10245 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10249 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10250 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10254 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10255 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10259 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10260 * when editable = true (defaults to false)
10262 selectOnFocus:false,
10264 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10266 queryParam: 'query',
10268 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10269 * when mode = 'remote' (defaults to 'Loading...')
10271 loadingText: 'Loading...',
10273 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10277 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10281 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10282 * traditional select (defaults to true)
10286 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10290 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10294 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10295 * listWidth has a higher value)
10299 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10300 * allow the user to set arbitrary text into the field (defaults to false)
10302 forceSelection:false,
10304 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10305 * if typeAhead = true (defaults to 250)
10307 typeAheadDelay : 250,
10309 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10310 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10312 valueNotFoundText : undefined,
10314 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10316 blockFocus : false,
10319 * @cfg {Boolean} disableClear Disable showing of clear button.
10321 disableClear : false,
10323 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10325 alwaysQuery : false,
10328 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10342 btnPosition : 'right',
10343 triggerList : true,
10344 // element that contains real text value.. (when hidden is used..)
10346 getAutoCreate : function()
10353 if(!this.tickable){
10354 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10359 * ComboBox with tickable selections
10362 var align = this.labelAlign || this.parentLabelAlign();
10365 cls : 'form-group roo-combobox-tickable' //input-group
10371 cls : 'tickable-buttons',
10376 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10383 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10390 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10397 Roo.each(buttons.cn, function(c){
10399 c.cls += ' btn-' + _this.size;
10402 if (_this.disabled) {
10413 cls: 'form-hidden-field'
10417 cls: 'select2-choices',
10421 cls: 'select2-search-field',
10433 cls: 'select2-container input-group select2-container-multi',
10438 // cls: 'typeahead typeahead-long dropdown-menu',
10439 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10444 if (align ==='left' && this.fieldLabel.length) {
10446 Roo.log("left and has label");
10452 cls : 'control-label col-sm-' + this.labelWidth,
10453 html : this.fieldLabel
10457 cls : "col-sm-" + (12 - this.labelWidth),
10464 } else if ( this.fieldLabel.length) {
10470 //cls : 'input-group-addon',
10471 html : this.fieldLabel
10481 Roo.log(" no label && no align");
10488 ['xs','sm','md','lg'].map(function(size){
10489 if (settings[size]) {
10490 cfg.cls += ' col-' + size + '-' + settings[size];
10499 initEvents: function()
10503 throw "can not find store for combo";
10505 this.store = Roo.factory(this.store, Roo.data);
10508 this.initTickableEvnets();
10512 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10514 if(this.hiddenName){
10516 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10518 this.hiddenField.dom.value =
10519 this.hiddenValue !== undefined ? this.hiddenValue :
10520 this.value !== undefined ? this.value : '';
10522 // prevent input submission
10523 this.el.dom.removeAttribute('name');
10524 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10529 // this.el.dom.setAttribute('autocomplete', 'off');
10532 var cls = 'x-combo-list';
10534 //this.list = new Roo.Layer({
10535 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10541 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10542 _this.list.setWidth(lw);
10545 this.list.on('mouseover', this.onViewOver, this);
10546 this.list.on('mousemove', this.onViewMove, this);
10548 this.list.on('scroll', this.onViewScroll, this);
10551 this.list.swallowEvent('mousewheel');
10552 this.assetHeight = 0;
10555 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10556 this.assetHeight += this.header.getHeight();
10559 this.innerList = this.list.createChild({cls:cls+'-inner'});
10560 this.innerList.on('mouseover', this.onViewOver, this);
10561 this.innerList.on('mousemove', this.onViewMove, this);
10562 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10564 if(this.allowBlank && !this.pageSize && !this.disableClear){
10565 this.footer = this.list.createChild({cls:cls+'-ft'});
10566 this.pageTb = new Roo.Toolbar(this.footer);
10570 this.footer = this.list.createChild({cls:cls+'-ft'});
10571 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10572 {pageSize: this.pageSize});
10576 if (this.pageTb && this.allowBlank && !this.disableClear) {
10578 this.pageTb.add(new Roo.Toolbar.Fill(), {
10579 cls: 'x-btn-icon x-btn-clear',
10581 handler: function()
10584 _this.clearValue();
10585 _this.onSelect(false, -1);
10590 this.assetHeight += this.footer.getHeight();
10595 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10598 this.view = new Roo.View(this.list, this.tpl, {
10599 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10601 //this.view.wrapEl.setDisplayed(false);
10602 this.view.on('click', this.onViewClick, this);
10606 this.store.on('beforeload', this.onBeforeLoad, this);
10607 this.store.on('load', this.onLoad, this);
10608 this.store.on('loadexception', this.onLoadException, this);
10610 if(this.resizable){
10611 this.resizer = new Roo.Resizable(this.list, {
10612 pinned:true, handles:'se'
10614 this.resizer.on('resize', function(r, w, h){
10615 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10616 this.listWidth = w;
10617 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10618 this.restrictHeight();
10620 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10623 if(!this.editable){
10624 this.editable = true;
10625 this.setEditable(false);
10630 if (typeof(this.events.add.listeners) != 'undefined') {
10632 this.addicon = this.wrap.createChild(
10633 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10635 this.addicon.on('click', function(e) {
10636 this.fireEvent('add', this);
10639 if (typeof(this.events.edit.listeners) != 'undefined') {
10641 this.editicon = this.wrap.createChild(
10642 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10643 if (this.addicon) {
10644 this.editicon.setStyle('margin-left', '40px');
10646 this.editicon.on('click', function(e) {
10648 // we fire even if inothing is selected..
10649 this.fireEvent('edit', this, this.lastData );
10655 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10656 "up" : function(e){
10657 this.inKeyMode = true;
10661 "down" : function(e){
10662 if(!this.isExpanded()){
10663 this.onTriggerClick();
10665 this.inKeyMode = true;
10670 "enter" : function(e){
10671 // this.onViewClick();
10675 if(this.fireEvent("specialkey", this, e)){
10676 this.onViewClick(false);
10682 "esc" : function(e){
10686 "tab" : function(e){
10689 if(this.fireEvent("specialkey", this, e)){
10690 this.onViewClick(false);
10698 doRelay : function(foo, bar, hname){
10699 if(hname == 'down' || this.scope.isExpanded()){
10700 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10709 this.queryDelay = Math.max(this.queryDelay || 10,
10710 this.mode == 'local' ? 10 : 250);
10713 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10715 if(this.typeAhead){
10716 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10718 if(this.editable !== false){
10719 this.inputEl().on("keyup", this.onKeyUp, this);
10721 if(this.forceSelection){
10722 this.inputEl().on('blur', this.doForce, this);
10726 this.choices = this.el.select('ul.select2-choices', true).first();
10727 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10731 initTickableEvnets: function()
10735 if(this.hiddenName){
10737 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10739 this.hiddenField.dom.value =
10740 this.hiddenValue !== undefined ? this.hiddenValue :
10741 this.value !== undefined ? this.value : '';
10743 // prevent input submission
10744 this.el.dom.removeAttribute('name');
10745 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10750 // this.list = this.el.select('ul.dropdown-menu',true).first();
10752 this.choices = this.el.select('ul.select2-choices', true).first();
10753 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10754 if(this.triggerList){
10755 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10758 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10759 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10761 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10762 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10764 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10765 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10767 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10768 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10769 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10772 this.cancelBtn.hide();
10777 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10778 _this.list.setWidth(lw);
10781 this.list.on('mouseover', this.onViewOver, this);
10782 this.list.on('mousemove', this.onViewMove, this);
10784 this.list.on('scroll', this.onViewScroll, this);
10787 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>';
10790 this.view = new Roo.View(this.list, this.tpl, {
10791 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10794 //this.view.wrapEl.setDisplayed(false);
10795 this.view.on('click', this.onViewClick, this);
10799 this.store.on('beforeload', this.onBeforeLoad, this);
10800 this.store.on('load', this.onLoad, this);
10801 this.store.on('loadexception', this.onLoadException, this);
10803 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10804 // "up" : function(e){
10805 // this.inKeyMode = true;
10806 // this.selectPrev();
10809 // "down" : function(e){
10810 // if(!this.isExpanded()){
10811 // this.onTriggerClick();
10813 // this.inKeyMode = true;
10814 // this.selectNext();
10818 // "enter" : function(e){
10819 //// this.onViewClick();
10821 // this.collapse();
10823 // if(this.fireEvent("specialkey", this, e)){
10824 // this.onViewClick(false);
10830 // "esc" : function(e){
10831 // this.collapse();
10834 // "tab" : function(e){
10835 // this.collapse();
10837 // if(this.fireEvent("specialkey", this, e)){
10838 // this.onViewClick(false);
10846 // doRelay : function(foo, bar, hname){
10847 // if(hname == 'down' || this.scope.isExpanded()){
10848 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10853 // forceKeyDown: true
10857 this.queryDelay = Math.max(this.queryDelay || 10,
10858 this.mode == 'local' ? 10 : 250);
10861 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10863 if(this.typeAhead){
10864 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10868 onDestroy : function(){
10870 this.view.setStore(null);
10871 this.view.el.removeAllListeners();
10872 this.view.el.remove();
10873 this.view.purgeListeners();
10876 this.list.dom.innerHTML = '';
10880 this.store.un('beforeload', this.onBeforeLoad, this);
10881 this.store.un('load', this.onLoad, this);
10882 this.store.un('loadexception', this.onLoadException, this);
10884 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10888 fireKey : function(e){
10889 if(e.isNavKeyPress() && !this.list.isVisible()){
10890 this.fireEvent("specialkey", this, e);
10895 onResize: function(w, h){
10896 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10898 // if(typeof w != 'number'){
10899 // // we do not handle it!?!?
10902 // var tw = this.trigger.getWidth();
10903 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10904 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10906 // this.inputEl().setWidth( this.adjustWidth('input', x));
10908 // //this.trigger.setStyle('left', x+'px');
10910 // if(this.list && this.listWidth === undefined){
10911 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10912 // this.list.setWidth(lw);
10913 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10921 * Allow or prevent the user from directly editing the field text. If false is passed,
10922 * the user will only be able to select from the items defined in the dropdown list. This method
10923 * is the runtime equivalent of setting the 'editable' config option at config time.
10924 * @param {Boolean} value True to allow the user to directly edit the field text
10926 setEditable : function(value){
10927 if(value == this.editable){
10930 this.editable = value;
10932 this.inputEl().dom.setAttribute('readOnly', true);
10933 this.inputEl().on('mousedown', this.onTriggerClick, this);
10934 this.inputEl().addClass('x-combo-noedit');
10936 this.inputEl().dom.setAttribute('readOnly', false);
10937 this.inputEl().un('mousedown', this.onTriggerClick, this);
10938 this.inputEl().removeClass('x-combo-noedit');
10944 onBeforeLoad : function(combo,opts){
10945 if(!this.hasFocus){
10949 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10951 // this.restrictHeight();
10952 this.selectedIndex = -1;
10956 onLoad : function(){
10958 this.hasQuery = false;
10960 if(!this.hasFocus){
10964 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10965 this.loading.hide();
10968 if(this.store.getCount() > 0){
10970 // this.restrictHeight();
10971 if(this.lastQuery == this.allQuery){
10972 if(this.editable && !this.tickable){
10973 this.inputEl().dom.select();
10975 if(!this.selectByValue(this.value, true) && this.autoFocus){
10976 this.select(0, true);
10979 if(this.autoFocus){
10982 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10983 this.taTask.delay(this.typeAheadDelay);
10987 this.onEmptyResults();
10993 onLoadException : function()
10995 this.hasQuery = false;
10997 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10998 this.loading.hide();
11002 Roo.log(this.store.reader.jsonData);
11003 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11005 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11011 onTypeAhead : function(){
11012 if(this.store.getCount() > 0){
11013 var r = this.store.getAt(0);
11014 var newValue = r.data[this.displayField];
11015 var len = newValue.length;
11016 var selStart = this.getRawValue().length;
11018 if(selStart != len){
11019 this.setRawValue(newValue);
11020 this.selectText(selStart, newValue.length);
11026 onSelect : function(record, index){
11028 if(this.fireEvent('beforeselect', this, record, index) !== false){
11030 this.setFromData(index > -1 ? record.data : false);
11033 this.fireEvent('select', this, record, index);
11038 * Returns the currently selected field value or empty string if no value is set.
11039 * @return {String} value The selected value
11041 getValue : function(){
11044 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11047 if(this.valueField){
11048 return typeof this.value != 'undefined' ? this.value : '';
11050 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11055 * Clears any text/value currently set in the field
11057 clearValue : function(){
11058 if(this.hiddenField){
11059 this.hiddenField.dom.value = '';
11062 this.setRawValue('');
11063 this.lastSelectionText = '';
11068 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11069 * will be displayed in the field. If the value does not match the data value of an existing item,
11070 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11071 * Otherwise the field will be blank (although the value will still be set).
11072 * @param {String} value The value to match
11074 setValue : function(v){
11081 if(this.valueField){
11082 var r = this.findRecord(this.valueField, v);
11084 text = r.data[this.displayField];
11085 }else if(this.valueNotFoundText !== undefined){
11086 text = this.valueNotFoundText;
11089 this.lastSelectionText = text;
11090 if(this.hiddenField){
11091 this.hiddenField.dom.value = v;
11093 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11097 * @property {Object} the last set data for the element
11102 * Sets the value of the field based on a object which is related to the record format for the store.
11103 * @param {Object} value the value to set as. or false on reset?
11105 setFromData : function(o){
11112 var dv = ''; // display value
11113 var vv = ''; // value value..
11115 if (this.displayField) {
11116 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11118 // this is an error condition!!!
11119 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11122 if(this.valueField){
11123 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11126 if(this.hiddenField){
11127 this.hiddenField.dom.value = vv;
11129 this.lastSelectionText = dv;
11130 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11134 // no hidden field.. - we store the value in 'value', but still display
11135 // display field!!!!
11136 this.lastSelectionText = dv;
11137 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11143 reset : function(){
11144 // overridden so that last data is reset..
11145 this.setValue(this.originalValue);
11146 this.clearInvalid();
11147 this.lastData = false;
11149 this.view.clearSelections();
11153 findRecord : function(prop, value){
11155 if(this.store.getCount() > 0){
11156 this.store.each(function(r){
11157 if(r.data[prop] == value){
11167 getName: function()
11169 // returns hidden if it's set..
11170 if (!this.rendered) {return ''};
11171 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11175 onViewMove : function(e, t){
11176 this.inKeyMode = false;
11180 onViewOver : function(e, t){
11181 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11184 var item = this.view.findItemFromChild(t);
11187 var index = this.view.indexOf(item);
11188 this.select(index, false);
11193 onViewClick : function(view, doFocus, el, e)
11195 var index = this.view.getSelectedIndexes()[0];
11197 var r = this.store.getAt(index);
11201 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11208 Roo.each(this.tickItems, function(v,k){
11210 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11211 _this.tickItems.splice(k, 1);
11221 this.tickItems.push(r.data);
11226 this.onSelect(r, index);
11228 if(doFocus !== false && !this.blockFocus){
11229 this.inputEl().focus();
11234 restrictHeight : function(){
11235 //this.innerList.dom.style.height = '';
11236 //var inner = this.innerList.dom;
11237 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11238 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11239 //this.list.beginUpdate();
11240 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11241 this.list.alignTo(this.inputEl(), this.listAlign);
11242 this.list.alignTo(this.inputEl(), this.listAlign);
11243 //this.list.endUpdate();
11247 onEmptyResults : function(){
11252 * Returns true if the dropdown list is expanded, else false.
11254 isExpanded : function(){
11255 return this.list.isVisible();
11259 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11260 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11261 * @param {String} value The data value of the item to select
11262 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11263 * selected item if it is not currently in view (defaults to true)
11264 * @return {Boolean} True if the value matched an item in the list, else false
11266 selectByValue : function(v, scrollIntoView){
11267 if(v !== undefined && v !== null){
11268 var r = this.findRecord(this.valueField || this.displayField, v);
11270 this.select(this.store.indexOf(r), scrollIntoView);
11278 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11279 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11280 * @param {Number} index The zero-based index of the list item to select
11281 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11282 * selected item if it is not currently in view (defaults to true)
11284 select : function(index, scrollIntoView){
11285 this.selectedIndex = index;
11286 this.view.select(index);
11287 if(scrollIntoView !== false){
11288 var el = this.view.getNode(index);
11289 if(el && !this.multiple && !this.tickable){
11290 this.list.scrollChildIntoView(el, false);
11296 selectNext : function(){
11297 var ct = this.store.getCount();
11299 if(this.selectedIndex == -1){
11301 }else if(this.selectedIndex < ct-1){
11302 this.select(this.selectedIndex+1);
11308 selectPrev : function(){
11309 var ct = this.store.getCount();
11311 if(this.selectedIndex == -1){
11313 }else if(this.selectedIndex != 0){
11314 this.select(this.selectedIndex-1);
11320 onKeyUp : function(e){
11321 if(this.editable !== false && !e.isSpecialKey()){
11322 this.lastKey = e.getKey();
11323 this.dqTask.delay(this.queryDelay);
11328 validateBlur : function(){
11329 return !this.list || !this.list.isVisible();
11333 initQuery : function(){
11334 this.doQuery(this.getRawValue());
11338 doForce : function(){
11339 if(this.inputEl().dom.value.length > 0){
11340 this.inputEl().dom.value =
11341 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11347 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11348 * query allowing the query action to be canceled if needed.
11349 * @param {String} query The SQL query to execute
11350 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11351 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11352 * saved in the current store (defaults to false)
11354 doQuery : function(q, forceAll){
11356 if(q === undefined || q === null){
11361 forceAll: forceAll,
11365 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11370 forceAll = qe.forceAll;
11371 if(forceAll === true || (q.length >= this.minChars)){
11373 this.hasQuery = true;
11375 if(this.lastQuery != q || this.alwaysQuery){
11376 this.lastQuery = q;
11377 if(this.mode == 'local'){
11378 this.selectedIndex = -1;
11380 this.store.clearFilter();
11382 this.store.filter(this.displayField, q);
11386 this.store.baseParams[this.queryParam] = q;
11388 var options = {params : this.getParams(q)};
11391 options.add = true;
11392 options.params.start = this.page * this.pageSize;
11395 this.store.load(options);
11397 * this code will make the page width larger, at the beginning, the list not align correctly,
11398 * we should expand the list on onLoad
11399 * so command out it
11404 this.selectedIndex = -1;
11409 this.loadNext = false;
11413 getParams : function(q){
11415 //p[this.queryParam] = q;
11419 p.limit = this.pageSize;
11425 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11427 collapse : function(){
11428 if(!this.isExpanded()){
11432 this.hasFocus = false;
11438 this.cancelBtn.hide();
11439 this.trigger.show();
11442 Roo.get(document).un('mousedown', this.collapseIf, this);
11443 Roo.get(document).un('mousewheel', this.collapseIf, this);
11444 if (!this.editable) {
11445 Roo.get(document).un('keydown', this.listKeyPress, this);
11447 this.fireEvent('collapse', this);
11451 collapseIf : function(e){
11452 var in_combo = e.within(this.el);
11453 var in_list = e.within(this.list);
11454 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11456 if (in_combo || in_list || is_list) {
11457 //e.stopPropagation();
11462 this.onTickableFooterButtonClick(e, false, false);
11470 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11472 expand : function(){
11474 if(this.isExpanded() || !this.hasFocus){
11481 this.restrictHeight();
11485 this.tickItems = Roo.apply([], this.item);
11488 this.cancelBtn.show();
11489 this.trigger.hide();
11493 Roo.get(document).on('mousedown', this.collapseIf, this);
11494 Roo.get(document).on('mousewheel', this.collapseIf, this);
11495 if (!this.editable) {
11496 Roo.get(document).on('keydown', this.listKeyPress, this);
11499 this.fireEvent('expand', this);
11503 // Implements the default empty TriggerField.onTriggerClick function
11504 onTriggerClick : function(e)
11506 Roo.log('trigger click');
11508 if(this.disabled || !this.triggerList){
11513 this.loadNext = false;
11515 if(this.isExpanded()){
11517 if (!this.blockFocus) {
11518 this.inputEl().focus();
11522 this.hasFocus = true;
11523 if(this.triggerAction == 'all') {
11524 this.doQuery(this.allQuery, true);
11526 this.doQuery(this.getRawValue());
11528 if (!this.blockFocus) {
11529 this.inputEl().focus();
11534 onTickableTriggerClick : function(e)
11541 this.loadNext = false;
11542 this.hasFocus = true;
11544 if(this.triggerAction == 'all') {
11545 this.doQuery(this.allQuery, true);
11547 this.doQuery(this.getRawValue());
11551 onSearchFieldClick : function(e)
11553 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11558 this.loadNext = false;
11559 this.hasFocus = true;
11561 if(this.triggerAction == 'all') {
11562 this.doQuery(this.allQuery, true);
11564 this.doQuery(this.getRawValue());
11568 listKeyPress : function(e)
11570 //Roo.log('listkeypress');
11571 // scroll to first matching element based on key pres..
11572 if (e.isSpecialKey()) {
11575 var k = String.fromCharCode(e.getKey()).toUpperCase();
11578 var csel = this.view.getSelectedNodes();
11579 var cselitem = false;
11581 var ix = this.view.indexOf(csel[0]);
11582 cselitem = this.store.getAt(ix);
11583 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11589 this.store.each(function(v) {
11591 // start at existing selection.
11592 if (cselitem.id == v.id) {
11598 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11599 match = this.store.indexOf(v);
11605 if (match === false) {
11606 return true; // no more action?
11609 this.view.select(match);
11610 var sn = Roo.get(this.view.getSelectedNodes()[0])
11611 //sn.scrollIntoView(sn.dom.parentNode, false);
11614 onViewScroll : function(e, t){
11616 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11620 this.hasQuery = true;
11622 this.loading = this.list.select('.loading', true).first();
11624 if(this.loading === null){
11625 this.list.createChild({
11627 cls: 'loading select2-more-results select2-active',
11628 html: 'Loading more results...'
11631 this.loading = this.list.select('.loading', true).first();
11633 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11635 this.loading.hide();
11638 this.loading.show();
11643 this.loadNext = true;
11645 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11650 addItem : function(o)
11652 var dv = ''; // display value
11654 if (this.displayField) {
11655 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11657 // this is an error condition!!!
11658 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11665 var choice = this.choices.createChild({
11667 cls: 'select2-search-choice',
11676 cls: 'select2-search-choice-close',
11681 }, this.searchField);
11683 var close = choice.select('a.select2-search-choice-close', true).first()
11685 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11693 this.inputEl().dom.value = '';
11697 onRemoveItem : function(e, _self, o)
11699 e.preventDefault();
11700 var index = this.item.indexOf(o.data) * 1;
11703 Roo.log('not this item?!');
11707 this.item.splice(index, 1);
11712 this.fireEvent('remove', this, e);
11716 syncValue : function()
11718 if(!this.item.length){
11725 Roo.each(this.item, function(i){
11726 if(_this.valueField){
11727 value.push(i[_this.valueField]);
11734 this.value = value.join(',');
11736 if(this.hiddenField){
11737 this.hiddenField.dom.value = this.value;
11741 clearItem : function()
11743 if(!this.multiple){
11749 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11756 inputEl: function ()
11759 return this.searchField;
11761 return this.el.select('input.form-control',true).first();
11765 onTickableFooterButtonClick : function(e, btn, el)
11767 e.preventDefault();
11769 if(btn && btn.name == 'cancel'){
11770 this.tickItems = Roo.apply([], this.item);
11779 Roo.each(this.tickItems, function(o){
11790 * @cfg {Boolean} grow
11794 * @cfg {Number} growMin
11798 * @cfg {Number} growMax
11808 * Ext JS Library 1.1.1
11809 * Copyright(c) 2006-2007, Ext JS, LLC.
11811 * Originally Released Under LGPL - original licence link has changed is not relivant.
11814 * <script type="text/javascript">
11819 * @extends Roo.util.Observable
11820 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11821 * This class also supports single and multi selection modes. <br>
11822 * Create a data model bound view:
11824 var store = new Roo.data.Store(...);
11826 var view = new Roo.View({
11828 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11830 singleSelect: true,
11831 selectedClass: "ydataview-selected",
11835 // listen for node click?
11836 view.on("click", function(vw, index, node, e){
11837 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11841 dataModel.load("foobar.xml");
11843 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11845 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11846 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11848 * Note: old style constructor is still suported (container, template, config)
11851 * Create a new View
11852 * @param {Object} config The config object
11855 Roo.View = function(config, depreciated_tpl, depreciated_config){
11857 this.parent = false;
11859 if (typeof(depreciated_tpl) == 'undefined') {
11860 // new way.. - universal constructor.
11861 Roo.apply(this, config);
11862 this.el = Roo.get(this.el);
11865 this.el = Roo.get(config);
11866 this.tpl = depreciated_tpl;
11867 Roo.apply(this, depreciated_config);
11869 this.wrapEl = this.el.wrap().wrap();
11870 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11873 if(typeof(this.tpl) == "string"){
11874 this.tpl = new Roo.Template(this.tpl);
11876 // support xtype ctors..
11877 this.tpl = new Roo.factory(this.tpl, Roo);
11881 this.tpl.compile();
11886 * @event beforeclick
11887 * Fires before a click is processed. Returns false to cancel the default action.
11888 * @param {Roo.View} this
11889 * @param {Number} index The index of the target node
11890 * @param {HTMLElement} node The target node
11891 * @param {Roo.EventObject} e The raw event object
11893 "beforeclick" : true,
11896 * Fires when a template node is clicked.
11897 * @param {Roo.View} this
11898 * @param {Number} index The index of the target node
11899 * @param {HTMLElement} node The target node
11900 * @param {Roo.EventObject} e The raw event object
11905 * Fires when a template node is double clicked.
11906 * @param {Roo.View} this
11907 * @param {Number} index The index of the target node
11908 * @param {HTMLElement} node The target node
11909 * @param {Roo.EventObject} e The raw event object
11913 * @event contextmenu
11914 * Fires when a template node is right clicked.
11915 * @param {Roo.View} this
11916 * @param {Number} index The index of the target node
11917 * @param {HTMLElement} node The target node
11918 * @param {Roo.EventObject} e The raw event object
11920 "contextmenu" : true,
11922 * @event selectionchange
11923 * Fires when the selected nodes change.
11924 * @param {Roo.View} this
11925 * @param {Array} selections Array of the selected nodes
11927 "selectionchange" : true,
11930 * @event beforeselect
11931 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11932 * @param {Roo.View} this
11933 * @param {HTMLElement} node The node to be selected
11934 * @param {Array} selections Array of currently selected nodes
11936 "beforeselect" : true,
11938 * @event preparedata
11939 * Fires on every row to render, to allow you to change the data.
11940 * @param {Roo.View} this
11941 * @param {Object} data to be rendered (change this)
11943 "preparedata" : true
11951 "click": this.onClick,
11952 "dblclick": this.onDblClick,
11953 "contextmenu": this.onContextMenu,
11957 this.selections = [];
11959 this.cmp = new Roo.CompositeElementLite([]);
11961 this.store = Roo.factory(this.store, Roo.data);
11962 this.setStore(this.store, true);
11965 if ( this.footer && this.footer.xtype) {
11967 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11969 this.footer.dataSource = this.store
11970 this.footer.container = fctr;
11971 this.footer = Roo.factory(this.footer, Roo);
11972 fctr.insertFirst(this.el);
11974 // this is a bit insane - as the paging toolbar seems to detach the el..
11975 // dom.parentNode.parentNode.parentNode
11976 // they get detached?
11980 Roo.View.superclass.constructor.call(this);
11985 Roo.extend(Roo.View, Roo.util.Observable, {
11988 * @cfg {Roo.data.Store} store Data store to load data from.
11993 * @cfg {String|Roo.Element} el The container element.
11998 * @cfg {String|Roo.Template} tpl The template used by this View
12002 * @cfg {String} dataName the named area of the template to use as the data area
12003 * Works with domtemplates roo-name="name"
12007 * @cfg {String} selectedClass The css class to add to selected nodes
12009 selectedClass : "x-view-selected",
12011 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12016 * @cfg {String} text to display on mask (default Loading)
12020 * @cfg {Boolean} multiSelect Allow multiple selection
12022 multiSelect : false,
12024 * @cfg {Boolean} singleSelect Allow single selection
12026 singleSelect: false,
12029 * @cfg {Boolean} toggleSelect - selecting
12031 toggleSelect : false,
12034 * @cfg {Boolean} tickable - selecting
12039 * Returns the element this view is bound to.
12040 * @return {Roo.Element}
12042 getEl : function(){
12043 return this.wrapEl;
12049 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12051 refresh : function(){
12052 Roo.log('refresh');
12055 // if we are using something like 'domtemplate', then
12056 // the what gets used is:
12057 // t.applySubtemplate(NAME, data, wrapping data..)
12058 // the outer template then get' applied with
12059 // the store 'extra data'
12060 // and the body get's added to the
12061 // roo-name="data" node?
12062 // <span class='roo-tpl-{name}'></span> ?????
12066 this.clearSelections();
12067 this.el.update("");
12069 var records = this.store.getRange();
12070 if(records.length < 1) {
12072 // is this valid?? = should it render a template??
12074 this.el.update(this.emptyText);
12078 if (this.dataName) {
12079 this.el.update(t.apply(this.store.meta)); //????
12080 el = this.el.child('.roo-tpl-' + this.dataName);
12083 for(var i = 0, len = records.length; i < len; i++){
12084 var data = this.prepareData(records[i].data, i, records[i]);
12085 this.fireEvent("preparedata", this, data, i, records[i]);
12087 var d = Roo.apply({}, data);
12090 Roo.apply(d, {'roo-id' : Roo.id()});
12094 Roo.each(this.parent.item, function(item){
12095 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12098 Roo.apply(d, {'roo-data-checked' : 'checked'});
12102 html[html.length] = Roo.util.Format.trim(
12104 t.applySubtemplate(this.dataName, d, this.store.meta) :
12111 el.update(html.join(""));
12112 this.nodes = el.dom.childNodes;
12113 this.updateIndexes(0);
12118 * Function to override to reformat the data that is sent to
12119 * the template for each node.
12120 * DEPRICATED - use the preparedata event handler.
12121 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12122 * a JSON object for an UpdateManager bound view).
12124 prepareData : function(data, index, record)
12126 this.fireEvent("preparedata", this, data, index, record);
12130 onUpdate : function(ds, record){
12131 Roo.log('on update');
12132 this.clearSelections();
12133 var index = this.store.indexOf(record);
12134 var n = this.nodes[index];
12135 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12136 n.parentNode.removeChild(n);
12137 this.updateIndexes(index, index);
12143 onAdd : function(ds, records, index)
12145 Roo.log(['on Add', ds, records, index] );
12146 this.clearSelections();
12147 if(this.nodes.length == 0){
12151 var n = this.nodes[index];
12152 for(var i = 0, len = records.length; i < len; i++){
12153 var d = this.prepareData(records[i].data, i, records[i]);
12155 this.tpl.insertBefore(n, d);
12158 this.tpl.append(this.el, d);
12161 this.updateIndexes(index);
12164 onRemove : function(ds, record, index){
12165 Roo.log('onRemove');
12166 this.clearSelections();
12167 var el = this.dataName ?
12168 this.el.child('.roo-tpl-' + this.dataName) :
12171 el.dom.removeChild(this.nodes[index]);
12172 this.updateIndexes(index);
12176 * Refresh an individual node.
12177 * @param {Number} index
12179 refreshNode : function(index){
12180 this.onUpdate(this.store, this.store.getAt(index));
12183 updateIndexes : function(startIndex, endIndex){
12184 var ns = this.nodes;
12185 startIndex = startIndex || 0;
12186 endIndex = endIndex || ns.length - 1;
12187 for(var i = startIndex; i <= endIndex; i++){
12188 ns[i].nodeIndex = i;
12193 * Changes the data store this view uses and refresh the view.
12194 * @param {Store} store
12196 setStore : function(store, initial){
12197 if(!initial && this.store){
12198 this.store.un("datachanged", this.refresh);
12199 this.store.un("add", this.onAdd);
12200 this.store.un("remove", this.onRemove);
12201 this.store.un("update", this.onUpdate);
12202 this.store.un("clear", this.refresh);
12203 this.store.un("beforeload", this.onBeforeLoad);
12204 this.store.un("load", this.onLoad);
12205 this.store.un("loadexception", this.onLoad);
12209 store.on("datachanged", this.refresh, this);
12210 store.on("add", this.onAdd, this);
12211 store.on("remove", this.onRemove, this);
12212 store.on("update", this.onUpdate, this);
12213 store.on("clear", this.refresh, this);
12214 store.on("beforeload", this.onBeforeLoad, this);
12215 store.on("load", this.onLoad, this);
12216 store.on("loadexception", this.onLoad, this);
12224 * onbeforeLoad - masks the loading area.
12227 onBeforeLoad : function(store,opts)
12229 Roo.log('onBeforeLoad');
12231 this.el.update("");
12233 this.el.mask(this.mask ? this.mask : "Loading" );
12235 onLoad : function ()
12242 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12243 * @param {HTMLElement} node
12244 * @return {HTMLElement} The template node
12246 findItemFromChild : function(node){
12247 var el = this.dataName ?
12248 this.el.child('.roo-tpl-' + this.dataName,true) :
12251 if(!node || node.parentNode == el){
12254 var p = node.parentNode;
12255 while(p && p != el){
12256 if(p.parentNode == el){
12265 onClick : function(e){
12266 var item = this.findItemFromChild(e.getTarget());
12268 var index = this.indexOf(item);
12269 if(this.onItemClick(item, index, e) !== false){
12270 this.fireEvent("click", this, index, item, e);
12273 this.clearSelections();
12278 onContextMenu : function(e){
12279 var item = this.findItemFromChild(e.getTarget());
12281 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12286 onDblClick : function(e){
12287 var item = this.findItemFromChild(e.getTarget());
12289 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12293 onItemClick : function(item, index, e)
12295 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12298 if (this.toggleSelect) {
12299 var m = this.isSelected(item) ? 'unselect' : 'select';
12302 _t[m](item, true, false);
12305 if(this.multiSelect || this.singleSelect){
12306 if(this.multiSelect && e.shiftKey && this.lastSelection){
12307 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12309 this.select(item, this.multiSelect && e.ctrlKey);
12310 this.lastSelection = item;
12313 if(!this.tickable){
12314 e.preventDefault();
12322 * Get the number of selected nodes.
12325 getSelectionCount : function(){
12326 return this.selections.length;
12330 * Get the currently selected nodes.
12331 * @return {Array} An array of HTMLElements
12333 getSelectedNodes : function(){
12334 return this.selections;
12338 * Get the indexes of the selected nodes.
12341 getSelectedIndexes : function(){
12342 var indexes = [], s = this.selections;
12343 for(var i = 0, len = s.length; i < len; i++){
12344 indexes.push(s[i].nodeIndex);
12350 * Clear all selections
12351 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12353 clearSelections : function(suppressEvent){
12354 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12355 this.cmp.elements = this.selections;
12356 this.cmp.removeClass(this.selectedClass);
12357 this.selections = [];
12358 if(!suppressEvent){
12359 this.fireEvent("selectionchange", this, this.selections);
12365 * Returns true if the passed node is selected
12366 * @param {HTMLElement/Number} node The node or node index
12367 * @return {Boolean}
12369 isSelected : function(node){
12370 var s = this.selections;
12374 node = this.getNode(node);
12375 return s.indexOf(node) !== -1;
12380 * @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
12381 * @param {Boolean} keepExisting (optional) true to keep existing selections
12382 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12384 select : function(nodeInfo, keepExisting, suppressEvent){
12385 if(nodeInfo instanceof Array){
12387 this.clearSelections(true);
12389 for(var i = 0, len = nodeInfo.length; i < len; i++){
12390 this.select(nodeInfo[i], true, true);
12394 var node = this.getNode(nodeInfo);
12395 if(!node || this.isSelected(node)){
12396 return; // already selected.
12399 this.clearSelections(true);
12401 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12402 Roo.fly(node).addClass(this.selectedClass);
12403 this.selections.push(node);
12404 if(!suppressEvent){
12405 this.fireEvent("selectionchange", this, this.selections);
12413 * @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
12414 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12415 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12417 unselect : function(nodeInfo, keepExisting, suppressEvent)
12419 if(nodeInfo instanceof Array){
12420 Roo.each(this.selections, function(s) {
12421 this.unselect(s, nodeInfo);
12425 var node = this.getNode(nodeInfo);
12426 if(!node || !this.isSelected(node)){
12427 Roo.log("not selected");
12428 return; // not selected.
12432 Roo.each(this.selections, function(s) {
12434 Roo.fly(node).removeClass(this.selectedClass);
12441 this.selections= ns;
12442 this.fireEvent("selectionchange", this, this.selections);
12446 * Gets a template node.
12447 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12448 * @return {HTMLElement} The node or null if it wasn't found
12450 getNode : function(nodeInfo){
12451 if(typeof nodeInfo == "string"){
12452 return document.getElementById(nodeInfo);
12453 }else if(typeof nodeInfo == "number"){
12454 return this.nodes[nodeInfo];
12460 * Gets a range template nodes.
12461 * @param {Number} startIndex
12462 * @param {Number} endIndex
12463 * @return {Array} An array of nodes
12465 getNodes : function(start, end){
12466 var ns = this.nodes;
12467 start = start || 0;
12468 end = typeof end == "undefined" ? ns.length - 1 : end;
12471 for(var i = start; i <= end; i++){
12475 for(var i = start; i >= end; i--){
12483 * Finds the index of the passed node
12484 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12485 * @return {Number} The index of the node or -1
12487 indexOf : function(node){
12488 node = this.getNode(node);
12489 if(typeof node.nodeIndex == "number"){
12490 return node.nodeIndex;
12492 var ns = this.nodes;
12493 for(var i = 0, len = ns.length; i < len; i++){
12504 * based on jquery fullcalendar
12508 Roo.bootstrap = Roo.bootstrap || {};
12510 * @class Roo.bootstrap.Calendar
12511 * @extends Roo.bootstrap.Component
12512 * Bootstrap Calendar class
12513 * @cfg {Boolean} loadMask (true|false) default false
12514 * @cfg {Object} header generate the user specific header of the calendar, default false
12517 * Create a new Container
12518 * @param {Object} config The config object
12523 Roo.bootstrap.Calendar = function(config){
12524 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12528 * Fires when a date is selected
12529 * @param {DatePicker} this
12530 * @param {Date} date The selected date
12534 * @event monthchange
12535 * Fires when the displayed month changes
12536 * @param {DatePicker} this
12537 * @param {Date} date The selected month
12539 'monthchange': true,
12541 * @event evententer
12542 * Fires when mouse over an event
12543 * @param {Calendar} this
12544 * @param {event} Event
12546 'evententer': true,
12548 * @event eventleave
12549 * Fires when the mouse leaves an
12550 * @param {Calendar} this
12553 'eventleave': true,
12555 * @event eventclick
12556 * Fires when the mouse click an
12557 * @param {Calendar} this
12566 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12569 * @cfg {Number} startDay
12570 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12578 getAutoCreate : function(){
12581 var fc_button = function(name, corner, style, content ) {
12582 return Roo.apply({},{
12584 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12586 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12589 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12600 style : 'width:100%',
12607 cls : 'fc-header-left',
12609 fc_button('prev', 'left', 'arrow', '‹' ),
12610 fc_button('next', 'right', 'arrow', '›' ),
12611 { tag: 'span', cls: 'fc-header-space' },
12612 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12620 cls : 'fc-header-center',
12624 cls: 'fc-header-title',
12627 html : 'month / year'
12635 cls : 'fc-header-right',
12637 /* fc_button('month', 'left', '', 'month' ),
12638 fc_button('week', '', '', 'week' ),
12639 fc_button('day', 'right', '', 'day' )
12651 header = this.header;
12654 var cal_heads = function() {
12656 // fixme - handle this.
12658 for (var i =0; i < Date.dayNames.length; i++) {
12659 var d = Date.dayNames[i];
12662 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12663 html : d.substring(0,3)
12667 ret[0].cls += ' fc-first';
12668 ret[6].cls += ' fc-last';
12671 var cal_cell = function(n) {
12674 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12679 cls: 'fc-day-number',
12683 cls: 'fc-day-content',
12687 style: 'position: relative;' // height: 17px;
12699 var cal_rows = function() {
12702 for (var r = 0; r < 6; r++) {
12709 for (var i =0; i < Date.dayNames.length; i++) {
12710 var d = Date.dayNames[i];
12711 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12714 row.cn[0].cls+=' fc-first';
12715 row.cn[0].cn[0].style = 'min-height:90px';
12716 row.cn[6].cls+=' fc-last';
12720 ret[0].cls += ' fc-first';
12721 ret[4].cls += ' fc-prev-last';
12722 ret[5].cls += ' fc-last';
12729 cls: 'fc-border-separate',
12730 style : 'width:100%',
12738 cls : 'fc-first fc-last',
12756 cls : 'fc-content',
12757 style : "position: relative;",
12760 cls : 'fc-view fc-view-month fc-grid',
12761 style : 'position: relative',
12762 unselectable : 'on',
12765 cls : 'fc-event-container',
12766 style : 'position:absolute;z-index:8;top:0;left:0;'
12784 initEvents : function()
12787 throw "can not find store for calendar";
12793 style: "text-align:center",
12797 style: "background-color:white;width:50%;margin:250 auto",
12801 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12812 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12814 var size = this.el.select('.fc-content', true).first().getSize();
12815 this.maskEl.setSize(size.width, size.height);
12816 this.maskEl.enableDisplayMode("block");
12817 if(!this.loadMask){
12818 this.maskEl.hide();
12821 this.store = Roo.factory(this.store, Roo.data);
12822 this.store.on('load', this.onLoad, this);
12823 this.store.on('beforeload', this.onBeforeLoad, this);
12827 this.cells = this.el.select('.fc-day',true);
12828 //Roo.log(this.cells);
12829 this.textNodes = this.el.query('.fc-day-number');
12830 this.cells.addClassOnOver('fc-state-hover');
12832 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12833 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12834 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12835 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12837 this.on('monthchange', this.onMonthChange, this);
12839 this.update(new Date().clearTime());
12842 resize : function() {
12843 var sz = this.el.getSize();
12845 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12846 this.el.select('.fc-day-content div',true).setHeight(34);
12851 showPrevMonth : function(e){
12852 this.update(this.activeDate.add("mo", -1));
12854 showToday : function(e){
12855 this.update(new Date().clearTime());
12858 showNextMonth : function(e){
12859 this.update(this.activeDate.add("mo", 1));
12863 showPrevYear : function(){
12864 this.update(this.activeDate.add("y", -1));
12868 showNextYear : function(){
12869 this.update(this.activeDate.add("y", 1));
12874 update : function(date)
12876 var vd = this.activeDate;
12877 this.activeDate = date;
12878 // if(vd && this.el){
12879 // var t = date.getTime();
12880 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12881 // Roo.log('using add remove');
12883 // this.fireEvent('monthchange', this, date);
12885 // this.cells.removeClass("fc-state-highlight");
12886 // this.cells.each(function(c){
12887 // if(c.dateValue == t){
12888 // c.addClass("fc-state-highlight");
12889 // setTimeout(function(){
12890 // try{c.dom.firstChild.focus();}catch(e){}
12900 var days = date.getDaysInMonth();
12902 var firstOfMonth = date.getFirstDateOfMonth();
12903 var startingPos = firstOfMonth.getDay()-this.startDay;
12905 if(startingPos < this.startDay){
12909 var pm = date.add(Date.MONTH, -1);
12910 var prevStart = pm.getDaysInMonth()-startingPos;
12912 this.cells = this.el.select('.fc-day',true);
12913 this.textNodes = this.el.query('.fc-day-number');
12914 this.cells.addClassOnOver('fc-state-hover');
12916 var cells = this.cells.elements;
12917 var textEls = this.textNodes;
12919 Roo.each(cells, function(cell){
12920 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12923 days += startingPos;
12925 // convert everything to numbers so it's fast
12926 var day = 86400000;
12927 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12930 //Roo.log(prevStart);
12932 var today = new Date().clearTime().getTime();
12933 var sel = date.clearTime().getTime();
12934 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12935 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12936 var ddMatch = this.disabledDatesRE;
12937 var ddText = this.disabledDatesText;
12938 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12939 var ddaysText = this.disabledDaysText;
12940 var format = this.format;
12942 var setCellClass = function(cal, cell){
12946 //Roo.log('set Cell Class');
12948 var t = d.getTime();
12952 cell.dateValue = t;
12954 cell.className += " fc-today";
12955 cell.className += " fc-state-highlight";
12956 cell.title = cal.todayText;
12959 // disable highlight in other month..
12960 //cell.className += " fc-state-highlight";
12965 cell.className = " fc-state-disabled";
12966 cell.title = cal.minText;
12970 cell.className = " fc-state-disabled";
12971 cell.title = cal.maxText;
12975 if(ddays.indexOf(d.getDay()) != -1){
12976 cell.title = ddaysText;
12977 cell.className = " fc-state-disabled";
12980 if(ddMatch && format){
12981 var fvalue = d.dateFormat(format);
12982 if(ddMatch.test(fvalue)){
12983 cell.title = ddText.replace("%0", fvalue);
12984 cell.className = " fc-state-disabled";
12988 if (!cell.initialClassName) {
12989 cell.initialClassName = cell.dom.className;
12992 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12997 for(; i < startingPos; i++) {
12998 textEls[i].innerHTML = (++prevStart);
12999 d.setDate(d.getDate()+1);
13001 cells[i].className = "fc-past fc-other-month";
13002 setCellClass(this, cells[i]);
13007 for(; i < days; i++){
13008 intDay = i - startingPos + 1;
13009 textEls[i].innerHTML = (intDay);
13010 d.setDate(d.getDate()+1);
13012 cells[i].className = ''; // "x-date-active";
13013 setCellClass(this, cells[i]);
13017 for(; i < 42; i++) {
13018 textEls[i].innerHTML = (++extraDays);
13019 d.setDate(d.getDate()+1);
13021 cells[i].className = "fc-future fc-other-month";
13022 setCellClass(this, cells[i]);
13025 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13027 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13029 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13030 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13032 if(totalRows != 6){
13033 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13034 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13037 this.fireEvent('monthchange', this, date);
13041 if(!this.internalRender){
13042 var main = this.el.dom.firstChild;
13043 var w = main.offsetWidth;
13044 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13045 Roo.fly(main).setWidth(w);
13046 this.internalRender = true;
13047 // opera does not respect the auto grow header center column
13048 // then, after it gets a width opera refuses to recalculate
13049 // without a second pass
13050 if(Roo.isOpera && !this.secondPass){
13051 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13052 this.secondPass = true;
13053 this.update.defer(10, this, [date]);
13060 findCell : function(dt) {
13061 dt = dt.clearTime().getTime();
13063 this.cells.each(function(c){
13064 //Roo.log("check " +c.dateValue + '?=' + dt);
13065 if(c.dateValue == dt){
13075 findCells : function(ev) {
13076 var s = ev.start.clone().clearTime().getTime();
13078 var e= ev.end.clone().clearTime().getTime();
13081 this.cells.each(function(c){
13082 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13084 if(c.dateValue > e){
13087 if(c.dateValue < s){
13096 // findBestRow: function(cells)
13100 // for (var i =0 ; i < cells.length;i++) {
13101 // ret = Math.max(cells[i].rows || 0,ret);
13108 addItem : function(ev)
13110 // look for vertical location slot in
13111 var cells = this.findCells(ev);
13113 // ev.row = this.findBestRow(cells);
13115 // work out the location.
13119 for(var i =0; i < cells.length; i++) {
13121 cells[i].row = cells[0].row;
13124 cells[i].row = cells[i].row + 1;
13134 if (crow.start.getY() == cells[i].getY()) {
13136 crow.end = cells[i];
13153 cells[0].events.push(ev);
13155 this.calevents.push(ev);
13158 clearEvents: function() {
13160 if(!this.calevents){
13164 Roo.each(this.cells.elements, function(c){
13170 Roo.each(this.calevents, function(e) {
13171 Roo.each(e.els, function(el) {
13172 el.un('mouseenter' ,this.onEventEnter, this);
13173 el.un('mouseleave' ,this.onEventLeave, this);
13178 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13184 renderEvents: function()
13188 this.cells.each(function(c) {
13197 if(c.row != c.events.length){
13198 r = 4 - (4 - (c.row - c.events.length));
13201 c.events = ev.slice(0, r);
13202 c.more = ev.slice(r);
13204 if(c.more.length && c.more.length == 1){
13205 c.events.push(c.more.pop());
13208 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13212 this.cells.each(function(c) {
13214 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13217 for (var e = 0; e < c.events.length; e++){
13218 var ev = c.events[e];
13219 var rows = ev.rows;
13221 for(var i = 0; i < rows.length; i++) {
13223 // how many rows should it span..
13226 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13227 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13229 unselectable : "on",
13232 cls: 'fc-event-inner',
13236 // cls: 'fc-event-time',
13237 // html : cells.length > 1 ? '' : ev.time
13241 cls: 'fc-event-title',
13242 html : String.format('{0}', ev.title)
13249 cls: 'ui-resizable-handle ui-resizable-e',
13250 html : '  '
13257 cfg.cls += ' fc-event-start';
13259 if ((i+1) == rows.length) {
13260 cfg.cls += ' fc-event-end';
13263 var ctr = _this.el.select('.fc-event-container',true).first();
13264 var cg = ctr.createChild(cfg);
13266 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13267 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13269 var r = (c.more.length) ? 1 : 0;
13270 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13271 cg.setWidth(ebox.right - sbox.x -2);
13273 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13274 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13275 cg.on('click', _this.onEventClick, _this, ev);
13286 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13287 style : 'position: absolute',
13288 unselectable : "on",
13291 cls: 'fc-event-inner',
13295 cls: 'fc-event-title',
13303 cls: 'ui-resizable-handle ui-resizable-e',
13304 html : '  '
13310 var ctr = _this.el.select('.fc-event-container',true).first();
13311 var cg = ctr.createChild(cfg);
13313 var sbox = c.select('.fc-day-content',true).first().getBox();
13314 var ebox = c.select('.fc-day-content',true).first().getBox();
13316 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13317 cg.setWidth(ebox.right - sbox.x -2);
13319 cg.on('click', _this.onMoreEventClick, _this, c.more);
13329 onEventEnter: function (e, el,event,d) {
13330 this.fireEvent('evententer', this, el, event);
13333 onEventLeave: function (e, el,event,d) {
13334 this.fireEvent('eventleave', this, el, event);
13337 onEventClick: function (e, el,event,d) {
13338 this.fireEvent('eventclick', this, el, event);
13341 onMonthChange: function () {
13345 onMoreEventClick: function(e, el, more)
13349 this.calpopover.placement = 'right';
13350 this.calpopover.setTitle('More');
13352 this.calpopover.setContent('');
13354 var ctr = this.calpopover.el.select('.popover-content', true).first();
13356 Roo.each(more, function(m){
13358 cls : 'fc-event-hori fc-event-draggable',
13361 var cg = ctr.createChild(cfg);
13363 cg.on('click', _this.onEventClick, _this, m);
13366 this.calpopover.show(el);
13371 onLoad: function ()
13373 this.calevents = [];
13376 if(this.store.getCount() > 0){
13377 this.store.data.each(function(d){
13380 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13381 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13382 time : d.data.start_time,
13383 title : d.data.title,
13384 description : d.data.description,
13385 venue : d.data.venue
13390 this.renderEvents();
13392 if(this.calevents.length && this.loadMask){
13393 this.maskEl.hide();
13397 onBeforeLoad: function()
13399 this.clearEvents();
13401 this.maskEl.show();
13415 * @class Roo.bootstrap.Popover
13416 * @extends Roo.bootstrap.Component
13417 * Bootstrap Popover class
13418 * @cfg {String} html contents of the popover (or false to use children..)
13419 * @cfg {String} title of popover (or false to hide)
13420 * @cfg {String} placement how it is placed
13421 * @cfg {String} trigger click || hover (or false to trigger manually)
13422 * @cfg {String} over what (parent or false to trigger manually.)
13425 * Create a new Popover
13426 * @param {Object} config The config object
13429 Roo.bootstrap.Popover = function(config){
13430 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13433 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13435 title: 'Fill in a title',
13438 placement : 'right',
13439 trigger : 'hover', // hover
13443 can_build_overlaid : false,
13445 getChildContainer : function()
13447 return this.el.select('.popover-content',true).first();
13450 getAutoCreate : function(){
13451 Roo.log('make popover?');
13453 cls : 'popover roo-dynamic',
13454 style: 'display:block',
13460 cls : 'popover-inner',
13464 cls: 'popover-title',
13468 cls : 'popover-content',
13479 setTitle: function(str)
13481 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13483 setContent: function(str)
13485 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13487 // as it get's added to the bottom of the page.
13488 onRender : function(ct, position)
13490 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13492 var cfg = Roo.apply({}, this.getAutoCreate());
13496 cfg.cls += ' ' + this.cls;
13499 cfg.style = this.style;
13501 Roo.log("adding to ")
13502 this.el = Roo.get(document.body).createChild(cfg, position);
13508 initEvents : function()
13510 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13511 this.el.enableDisplayMode('block');
13513 if (this.over === false) {
13516 if (this.triggers === false) {
13519 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13520 var triggers = this.trigger ? this.trigger.split(' ') : [];
13521 Roo.each(triggers, function(trigger) {
13523 if (trigger == 'click') {
13524 on_el.on('click', this.toggle, this);
13525 } else if (trigger != 'manual') {
13526 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13527 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13529 on_el.on(eventIn ,this.enter, this);
13530 on_el.on(eventOut, this.leave, this);
13541 toggle : function () {
13542 this.hoverState == 'in' ? this.leave() : this.enter();
13545 enter : function () {
13548 clearTimeout(this.timeout);
13550 this.hoverState = 'in'
13552 if (!this.delay || !this.delay.show) {
13557 this.timeout = setTimeout(function () {
13558 if (_t.hoverState == 'in') {
13561 }, this.delay.show)
13563 leave : function() {
13564 clearTimeout(this.timeout);
13566 this.hoverState = 'out'
13568 if (!this.delay || !this.delay.hide) {
13573 this.timeout = setTimeout(function () {
13574 if (_t.hoverState == 'out') {
13577 }, this.delay.hide)
13580 show : function (on_el)
13583 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13586 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13587 if (this.html !== false) {
13588 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13590 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13591 if (!this.title.length) {
13592 this.el.select('.popover-title',true).hide();
13595 var placement = typeof this.placement == 'function' ?
13596 this.placement.call(this, this.el, on_el) :
13599 var autoToken = /\s?auto?\s?/i;
13600 var autoPlace = autoToken.test(placement);
13602 placement = placement.replace(autoToken, '') || 'top';
13606 //this.el.setXY([0,0]);
13608 this.el.dom.style.display='block';
13609 this.el.addClass(placement);
13611 //this.el.appendTo(on_el);
13613 var p = this.getPosition();
13614 var box = this.el.getBox();
13619 var align = Roo.bootstrap.Popover.alignment[placement]
13620 this.el.alignTo(on_el, align[0],align[1]);
13621 //var arrow = this.el.select('.arrow',true).first();
13622 //arrow.set(align[2],
13624 this.el.addClass('in');
13625 this.hoverState = null;
13627 if (this.el.hasClass('fade')) {
13634 this.el.setXY([0,0]);
13635 this.el.removeClass('in');
13642 Roo.bootstrap.Popover.alignment = {
13643 'left' : ['r-l', [-10,0], 'right'],
13644 'right' : ['l-r', [10,0], 'left'],
13645 'bottom' : ['t-b', [0,10], 'top'],
13646 'top' : [ 'b-t', [0,-10], 'bottom']
13657 * @class Roo.bootstrap.Progress
13658 * @extends Roo.bootstrap.Component
13659 * Bootstrap Progress class
13660 * @cfg {Boolean} striped striped of the progress bar
13661 * @cfg {Boolean} active animated of the progress bar
13665 * Create a new Progress
13666 * @param {Object} config The config object
13669 Roo.bootstrap.Progress = function(config){
13670 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13673 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13678 getAutoCreate : function(){
13686 cfg.cls += ' progress-striped';
13690 cfg.cls += ' active';
13709 * @class Roo.bootstrap.ProgressBar
13710 * @extends Roo.bootstrap.Component
13711 * Bootstrap ProgressBar class
13712 * @cfg {Number} aria_valuenow aria-value now
13713 * @cfg {Number} aria_valuemin aria-value min
13714 * @cfg {Number} aria_valuemax aria-value max
13715 * @cfg {String} label label for the progress bar
13716 * @cfg {String} panel (success | info | warning | danger )
13717 * @cfg {String} role role of the progress bar
13718 * @cfg {String} sr_only text
13722 * Create a new ProgressBar
13723 * @param {Object} config The config object
13726 Roo.bootstrap.ProgressBar = function(config){
13727 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13730 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13734 aria_valuemax : 100,
13740 getAutoCreate : function()
13745 cls: 'progress-bar',
13746 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13758 cfg.role = this.role;
13761 if(this.aria_valuenow){
13762 cfg['aria-valuenow'] = this.aria_valuenow;
13765 if(this.aria_valuemin){
13766 cfg['aria-valuemin'] = this.aria_valuemin;
13769 if(this.aria_valuemax){
13770 cfg['aria-valuemax'] = this.aria_valuemax;
13773 if(this.label && !this.sr_only){
13774 cfg.html = this.label;
13778 cfg.cls += ' progress-bar-' + this.panel;
13784 update : function(aria_valuenow)
13786 this.aria_valuenow = aria_valuenow;
13788 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13803 * @class Roo.bootstrap.TabGroup
13804 * @extends Roo.bootstrap.Column
13805 * Bootstrap Column class
13806 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13807 * @cfg {Boolean} carousel true to make the group behave like a carousel
13810 * Create a new TabGroup
13811 * @param {Object} config The config object
13814 Roo.bootstrap.TabGroup = function(config){
13815 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13817 this.navId = Roo.id();
13820 Roo.bootstrap.TabGroup.register(this);
13824 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13827 transition : false,
13829 getAutoCreate : function()
13831 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13833 cfg.cls += ' tab-content';
13835 if (this.carousel) {
13836 cfg.cls += ' carousel slide';
13838 cls : 'carousel-inner'
13845 getChildContainer : function()
13847 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13851 * register a Navigation item
13852 * @param {Roo.bootstrap.NavItem} the navitem to add
13854 register : function(item)
13856 this.tabs.push( item);
13857 item.navId = this.navId; // not really needed..
13861 getActivePanel : function()
13864 Roo.each(this.tabs, function(t) {
13874 getPanelByName : function(n)
13877 Roo.each(this.tabs, function(t) {
13878 if (t.tabId == n) {
13886 indexOfPanel : function(p)
13889 Roo.each(this.tabs, function(t,i) {
13890 if (t.tabId == p.tabId) {
13899 * show a specific panel
13900 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13901 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13903 showPanel : function (pan)
13906 if (typeof(pan) == 'number') {
13907 pan = this.tabs[pan];
13909 if (typeof(pan) == 'string') {
13910 pan = this.getPanelByName(pan);
13912 if (pan.tabId == this.getActivePanel().tabId) {
13915 var cur = this.getActivePanel();
13917 if (false === cur.fireEvent('beforedeactivate')) {
13921 if (this.carousel) {
13922 this.transition = true;
13923 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13924 var lr = dir == 'next' ? 'left' : 'right';
13925 pan.el.addClass(dir); // or prev
13926 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13927 cur.el.addClass(lr); // or right
13928 pan.el.addClass(lr);
13931 cur.el.on('transitionend', function() {
13932 Roo.log("trans end?");
13934 pan.el.removeClass([lr,dir]);
13935 pan.setActive(true);
13937 cur.el.removeClass([lr]);
13938 cur.setActive(false);
13940 _this.transition = false;
13942 }, this, { single: true } );
13946 cur.setActive(false);
13947 pan.setActive(true);
13951 showPanelNext : function()
13953 var i = this.indexOfPanel(this.getActivePanel());
13954 if (i > this.tabs.length) {
13957 this.showPanel(this.tabs[i+1]);
13959 showPanelPrev : function()
13961 var i = this.indexOfPanel(this.getActivePanel());
13965 this.showPanel(this.tabs[i-1]);
13976 Roo.apply(Roo.bootstrap.TabGroup, {
13980 * register a Navigation Group
13981 * @param {Roo.bootstrap.NavGroup} the navgroup to add
13983 register : function(navgrp)
13985 this.groups[navgrp.navId] = navgrp;
13989 * fetch a Navigation Group based on the navigation ID
13990 * if one does not exist , it will get created.
13991 * @param {string} the navgroup to add
13992 * @returns {Roo.bootstrap.NavGroup} the navgroup
13994 get: function(navId) {
13995 if (typeof(this.groups[navId]) == 'undefined') {
13996 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
13998 return this.groups[navId] ;
14013 * @class Roo.bootstrap.TabPanel
14014 * @extends Roo.bootstrap.Component
14015 * Bootstrap TabPanel class
14016 * @cfg {Boolean} active panel active
14017 * @cfg {String} html panel content
14018 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14019 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14023 * Create a new TabPanel
14024 * @param {Object} config The config object
14027 Roo.bootstrap.TabPanel = function(config){
14028 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14032 * Fires when the active status changes
14033 * @param {Roo.bootstrap.TabPanel} this
14034 * @param {Boolean} state the new state
14039 * @event beforedeactivate
14040 * Fires before a tab is de-activated - can be used to do validation on a form.
14041 * @param {Roo.bootstrap.TabPanel} this
14042 * @return {Boolean} false if there is an error
14045 'beforedeactivate': true
14048 this.tabId = this.tabId || Roo.id();
14052 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14059 getAutoCreate : function(){
14062 // item is needed for carousel - not sure if it has any effect otherwise
14063 cls: 'tab-pane item',
14064 html: this.html || ''
14068 cfg.cls += ' active';
14072 cfg.tabId = this.tabId;
14079 initEvents: function()
14081 Roo.log('-------- init events on tab panel ---------');
14083 var p = this.parent();
14084 this.navId = this.navId || p.navId;
14086 if (typeof(this.navId) != 'undefined') {
14087 // not really needed.. but just in case.. parent should be a NavGroup.
14088 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14089 Roo.log(['register', tg, this]);
14095 onRender : function(ct, position)
14097 // Roo.log("Call onRender: " + this.xtype);
14099 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14107 setActive: function(state)
14109 Roo.log("panel - set active " + this.tabId + "=" + state);
14111 this.active = state;
14113 this.el.removeClass('active');
14115 } else if (!this.el.hasClass('active')) {
14116 this.el.addClass('active');
14118 this.fireEvent('changed', this, state);
14135 * @class Roo.bootstrap.DateField
14136 * @extends Roo.bootstrap.Input
14137 * Bootstrap DateField class
14138 * @cfg {Number} weekStart default 0
14139 * @cfg {Number} weekStart default 0
14140 * @cfg {Number} viewMode default empty, (months|years)
14141 * @cfg {Number} minViewMode default empty, (months|years)
14142 * @cfg {Number} startDate default -Infinity
14143 * @cfg {Number} endDate default Infinity
14144 * @cfg {Boolean} todayHighlight default false
14145 * @cfg {Boolean} todayBtn default false
14146 * @cfg {Boolean} calendarWeeks default false
14147 * @cfg {Object} daysOfWeekDisabled default empty
14149 * @cfg {Boolean} keyboardNavigation default true
14150 * @cfg {String} language default en
14153 * Create a new DateField
14154 * @param {Object} config The config object
14157 Roo.bootstrap.DateField = function(config){
14158 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14162 * Fires when this field show.
14163 * @param {Roo.bootstrap.DateField} this
14164 * @param {Mixed} date The date value
14169 * Fires when this field hide.
14170 * @param {Roo.bootstrap.DateField} this
14171 * @param {Mixed} date The date value
14176 * Fires when select a date.
14177 * @param {Roo.bootstrap.DateField} this
14178 * @param {Mixed} date The date value
14184 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14187 * @cfg {String} format
14188 * The default date format string which can be overriden for localization support. The format must be
14189 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14193 * @cfg {String} altFormats
14194 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14195 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14197 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14205 todayHighlight : false,
14211 keyboardNavigation: true,
14213 calendarWeeks: false,
14215 startDate: -Infinity,
14219 daysOfWeekDisabled: [],
14223 UTCDate: function()
14225 return new Date(Date.UTC.apply(Date, arguments));
14228 UTCToday: function()
14230 var today = new Date();
14231 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14234 getDate: function() {
14235 var d = this.getUTCDate();
14236 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14239 getUTCDate: function() {
14243 setDate: function(d) {
14244 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14247 setUTCDate: function(d) {
14249 this.setValue(this.formatDate(this.date));
14252 onRender: function(ct, position)
14255 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14257 this.language = this.language || 'en';
14258 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14259 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14261 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14262 this.format = this.format || 'm/d/y';
14263 this.isInline = false;
14264 this.isInput = true;
14265 this.component = this.el.select('.add-on', true).first() || false;
14266 this.component = (this.component && this.component.length === 0) ? false : this.component;
14267 this.hasInput = this.component && this.inputEL().length;
14269 if (typeof(this.minViewMode === 'string')) {
14270 switch (this.minViewMode) {
14272 this.minViewMode = 1;
14275 this.minViewMode = 2;
14278 this.minViewMode = 0;
14283 if (typeof(this.viewMode === 'string')) {
14284 switch (this.viewMode) {
14297 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14299 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14301 this.picker().on('mousedown', this.onMousedown, this);
14302 this.picker().on('click', this.onClick, this);
14304 this.picker().addClass('datepicker-dropdown');
14306 this.startViewMode = this.viewMode;
14309 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14310 if(!this.calendarWeeks){
14315 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14316 v.attr('colspan', function(i, val){
14317 return parseInt(val) + 1;
14322 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14324 this.setStartDate(this.startDate);
14325 this.setEndDate(this.endDate);
14327 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14334 if(this.isInline) {
14339 picker : function()
14341 return this.el.select('.datepicker', true).first();
14344 fillDow: function()
14346 var dowCnt = this.weekStart;
14355 if(this.calendarWeeks){
14363 while (dowCnt < this.weekStart + 7) {
14367 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14371 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14374 fillMonths: function()
14377 var months = this.picker().select('>.datepicker-months td', true).first();
14379 months.dom.innerHTML = '';
14385 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14388 months.createChild(month);
14396 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14398 if (this.date < this.startDate) {
14399 this.viewDate = new Date(this.startDate);
14400 } else if (this.date > this.endDate) {
14401 this.viewDate = new Date(this.endDate);
14403 this.viewDate = new Date(this.date);
14411 var d = new Date(this.viewDate),
14412 year = d.getUTCFullYear(),
14413 month = d.getUTCMonth(),
14414 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14415 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14416 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14417 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14418 currentDate = this.date && this.date.valueOf(),
14419 today = this.UTCToday();
14421 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14423 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14425 // this.picker.select('>tfoot th.today').
14426 // .text(dates[this.language].today)
14427 // .toggle(this.todayBtn !== false);
14429 this.updateNavArrows();
14432 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14434 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14436 prevMonth.setUTCDate(day);
14438 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14440 var nextMonth = new Date(prevMonth);
14442 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14444 nextMonth = nextMonth.valueOf();
14446 var fillMonths = false;
14448 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14450 while(prevMonth.valueOf() < nextMonth) {
14453 if (prevMonth.getUTCDay() === this.weekStart) {
14455 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14463 if(this.calendarWeeks){
14464 // ISO 8601: First week contains first thursday.
14465 // ISO also states week starts on Monday, but we can be more abstract here.
14467 // Start of current week: based on weekstart/current date
14468 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14469 // Thursday of this week
14470 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14471 // First Thursday of year, year from thursday
14472 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14473 // Calendar week: ms between thursdays, div ms per day, div 7 days
14474 calWeek = (th - yth) / 864e5 / 7 + 1;
14476 fillMonths.cn.push({
14484 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14486 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14489 if (this.todayHighlight &&
14490 prevMonth.getUTCFullYear() == today.getFullYear() &&
14491 prevMonth.getUTCMonth() == today.getMonth() &&
14492 prevMonth.getUTCDate() == today.getDate()) {
14493 clsName += ' today';
14496 if (currentDate && prevMonth.valueOf() === currentDate) {
14497 clsName += ' active';
14500 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14501 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14502 clsName += ' disabled';
14505 fillMonths.cn.push({
14507 cls: 'day ' + clsName,
14508 html: prevMonth.getDate()
14511 prevMonth.setDate(prevMonth.getDate()+1);
14514 var currentYear = this.date && this.date.getUTCFullYear();
14515 var currentMonth = this.date && this.date.getUTCMonth();
14517 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14519 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14520 v.removeClass('active');
14522 if(currentYear === year && k === currentMonth){
14523 v.addClass('active');
14526 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14527 v.addClass('disabled');
14533 year = parseInt(year/10, 10) * 10;
14535 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14537 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14540 for (var i = -1; i < 11; i++) {
14541 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14543 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14551 showMode: function(dir)
14554 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14556 Roo.each(this.picker().select('>div',true).elements, function(v){
14557 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14560 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14565 if(this.isInline) return;
14567 this.picker().removeClass(['bottom', 'top']);
14569 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14571 * place to the top of element!
14575 this.picker().addClass('top');
14576 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14581 this.picker().addClass('bottom');
14583 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14586 parseDate : function(value)
14588 if(!value || value instanceof Date){
14591 var v = Date.parseDate(value, this.format);
14592 if (!v && this.useIso) {
14593 v = Date.parseDate(value, 'Y-m-d');
14595 if(!v && this.altFormats){
14596 if(!this.altFormatsArray){
14597 this.altFormatsArray = this.altFormats.split("|");
14599 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14600 v = Date.parseDate(value, this.altFormatsArray[i]);
14606 formatDate : function(date, fmt)
14608 return (!date || !(date instanceof Date)) ?
14609 date : date.dateFormat(fmt || this.format);
14612 onFocus : function()
14614 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14618 onBlur : function()
14620 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14622 var d = this.inputEl().getValue();
14633 this.picker().show();
14637 this.fireEvent('show', this, this.date);
14642 if(this.isInline) return;
14643 this.picker().hide();
14644 this.viewMode = this.startViewMode;
14647 this.fireEvent('hide', this, this.date);
14651 onMousedown: function(e)
14653 e.stopPropagation();
14654 e.preventDefault();
14659 Roo.bootstrap.DateField.superclass.keyup.call(this);
14663 setValue: function(v)
14665 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14667 var d = new Date(v);
14669 if(isNaN(d.getTime())){
14673 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14677 this.fireEvent('select', this, this.date);
14681 getValue: function()
14683 return this.formatDate(this.date);
14686 fireKey: function(e)
14688 if (!this.picker().isVisible()){
14689 if (e.keyCode == 27) // allow escape to hide and re-show picker
14694 var dateChanged = false,
14696 newDate, newViewDate;
14701 e.preventDefault();
14705 if (!this.keyboardNavigation) break;
14706 dir = e.keyCode == 37 ? -1 : 1;
14709 newDate = this.moveYear(this.date, dir);
14710 newViewDate = this.moveYear(this.viewDate, dir);
14711 } else if (e.shiftKey){
14712 newDate = this.moveMonth(this.date, dir);
14713 newViewDate = this.moveMonth(this.viewDate, dir);
14715 newDate = new Date(this.date);
14716 newDate.setUTCDate(this.date.getUTCDate() + dir);
14717 newViewDate = new Date(this.viewDate);
14718 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14720 if (this.dateWithinRange(newDate)){
14721 this.date = newDate;
14722 this.viewDate = newViewDate;
14723 this.setValue(this.formatDate(this.date));
14725 e.preventDefault();
14726 dateChanged = true;
14731 if (!this.keyboardNavigation) break;
14732 dir = e.keyCode == 38 ? -1 : 1;
14734 newDate = this.moveYear(this.date, dir);
14735 newViewDate = this.moveYear(this.viewDate, dir);
14736 } else if (e.shiftKey){
14737 newDate = this.moveMonth(this.date, dir);
14738 newViewDate = this.moveMonth(this.viewDate, dir);
14740 newDate = new Date(this.date);
14741 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14742 newViewDate = new Date(this.viewDate);
14743 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14745 if (this.dateWithinRange(newDate)){
14746 this.date = newDate;
14747 this.viewDate = newViewDate;
14748 this.setValue(this.formatDate(this.date));
14750 e.preventDefault();
14751 dateChanged = true;
14755 this.setValue(this.formatDate(this.date));
14757 e.preventDefault();
14760 this.setValue(this.formatDate(this.date));
14774 onClick: function(e)
14776 e.stopPropagation();
14777 e.preventDefault();
14779 var target = e.getTarget();
14781 if(target.nodeName.toLowerCase() === 'i'){
14782 target = Roo.get(target).dom.parentNode;
14785 var nodeName = target.nodeName;
14786 var className = target.className;
14787 var html = target.innerHTML;
14789 switch(nodeName.toLowerCase()) {
14791 switch(className) {
14797 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14798 switch(this.viewMode){
14800 this.viewDate = this.moveMonth(this.viewDate, dir);
14804 this.viewDate = this.moveYear(this.viewDate, dir);
14810 var date = new Date();
14811 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14813 this.setValue(this.formatDate(this.date));
14820 if (className.indexOf('disabled') === -1) {
14821 this.viewDate.setUTCDate(1);
14822 if (className.indexOf('month') !== -1) {
14823 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14825 var year = parseInt(html, 10) || 0;
14826 this.viewDate.setUTCFullYear(year);
14835 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14836 var day = parseInt(html, 10) || 1;
14837 var year = this.viewDate.getUTCFullYear(),
14838 month = this.viewDate.getUTCMonth();
14840 if (className.indexOf('old') !== -1) {
14847 } else if (className.indexOf('new') !== -1) {
14855 this.date = this.UTCDate(year, month, day,0,0,0,0);
14856 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14858 this.setValue(this.formatDate(this.date));
14865 setStartDate: function(startDate)
14867 this.startDate = startDate || -Infinity;
14868 if (this.startDate !== -Infinity) {
14869 this.startDate = this.parseDate(this.startDate);
14872 this.updateNavArrows();
14875 setEndDate: function(endDate)
14877 this.endDate = endDate || Infinity;
14878 if (this.endDate !== Infinity) {
14879 this.endDate = this.parseDate(this.endDate);
14882 this.updateNavArrows();
14885 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14887 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14888 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14889 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14891 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14892 return parseInt(d, 10);
14895 this.updateNavArrows();
14898 updateNavArrows: function()
14900 var d = new Date(this.viewDate),
14901 year = d.getUTCFullYear(),
14902 month = d.getUTCMonth();
14904 Roo.each(this.picker().select('.prev', true).elements, function(v){
14906 switch (this.viewMode) {
14909 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14915 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14922 Roo.each(this.picker().select('.next', true).elements, function(v){
14924 switch (this.viewMode) {
14927 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14933 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14941 moveMonth: function(date, dir)
14943 if (!dir) return date;
14944 var new_date = new Date(date.valueOf()),
14945 day = new_date.getUTCDate(),
14946 month = new_date.getUTCMonth(),
14947 mag = Math.abs(dir),
14949 dir = dir > 0 ? 1 : -1;
14952 // If going back one month, make sure month is not current month
14953 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14955 return new_date.getUTCMonth() == month;
14957 // If going forward one month, make sure month is as expected
14958 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14960 return new_date.getUTCMonth() != new_month;
14962 new_month = month + dir;
14963 new_date.setUTCMonth(new_month);
14964 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14965 if (new_month < 0 || new_month > 11)
14966 new_month = (new_month + 12) % 12;
14968 // For magnitudes >1, move one month at a time...
14969 for (var i=0; i<mag; i++)
14970 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14971 new_date = this.moveMonth(new_date, dir);
14972 // ...then reset the day, keeping it in the new month
14973 new_month = new_date.getUTCMonth();
14974 new_date.setUTCDate(day);
14976 return new_month != new_date.getUTCMonth();
14979 // Common date-resetting loop -- if date is beyond end of month, make it
14982 new_date.setUTCDate(--day);
14983 new_date.setUTCMonth(new_month);
14988 moveYear: function(date, dir)
14990 return this.moveMonth(date, dir*12);
14993 dateWithinRange: function(date)
14995 return date >= this.startDate && date <= this.endDate;
15001 this.picker().remove();
15006 Roo.apply(Roo.bootstrap.DateField, {
15017 html: '<i class="fa fa-arrow-left"/>'
15027 html: '<i class="fa fa-arrow-right"/>'
15069 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15070 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15071 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15072 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15073 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15086 navFnc: 'FullYear',
15091 navFnc: 'FullYear',
15096 Roo.apply(Roo.bootstrap.DateField, {
15100 cls: 'datepicker dropdown-menu',
15104 cls: 'datepicker-days',
15108 cls: 'table-condensed',
15110 Roo.bootstrap.DateField.head,
15114 Roo.bootstrap.DateField.footer
15121 cls: 'datepicker-months',
15125 cls: 'table-condensed',
15127 Roo.bootstrap.DateField.head,
15128 Roo.bootstrap.DateField.content,
15129 Roo.bootstrap.DateField.footer
15136 cls: 'datepicker-years',
15140 cls: 'table-condensed',
15142 Roo.bootstrap.DateField.head,
15143 Roo.bootstrap.DateField.content,
15144 Roo.bootstrap.DateField.footer
15163 * @class Roo.bootstrap.TimeField
15164 * @extends Roo.bootstrap.Input
15165 * Bootstrap DateField class
15169 * Create a new TimeField
15170 * @param {Object} config The config object
15173 Roo.bootstrap.TimeField = function(config){
15174 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15178 * Fires when this field show.
15179 * @param {Roo.bootstrap.DateField} this
15180 * @param {Mixed} date The date value
15185 * Fires when this field hide.
15186 * @param {Roo.bootstrap.DateField} this
15187 * @param {Mixed} date The date value
15192 * Fires when select a date.
15193 * @param {Roo.bootstrap.DateField} this
15194 * @param {Mixed} date The date value
15200 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15203 * @cfg {String} format
15204 * The default time format string which can be overriden for localization support. The format must be
15205 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15209 onRender: function(ct, position)
15212 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15214 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15216 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15218 this.pop = this.picker().select('>.datepicker-time',true).first();
15219 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15221 this.picker().on('mousedown', this.onMousedown, this);
15222 this.picker().on('click', this.onClick, this);
15224 this.picker().addClass('datepicker-dropdown');
15229 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15230 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15231 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15232 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15233 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15234 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15238 fireKey: function(e){
15239 if (!this.picker().isVisible()){
15240 if (e.keyCode == 27) // allow escape to hide and re-show picker
15245 e.preventDefault();
15253 this.onTogglePeriod();
15256 this.onIncrementMinutes();
15259 this.onDecrementMinutes();
15268 onClick: function(e) {
15269 e.stopPropagation();
15270 e.preventDefault();
15273 picker : function()
15275 return this.el.select('.datepicker', true).first();
15278 fillTime: function()
15280 var time = this.pop.select('tbody', true).first();
15282 time.dom.innerHTML = '';
15297 cls: 'hours-up glyphicon glyphicon-chevron-up'
15317 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15338 cls: 'timepicker-hour',
15353 cls: 'timepicker-minute',
15368 cls: 'btn btn-primary period',
15390 cls: 'hours-down glyphicon glyphicon-chevron-down'
15410 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15428 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15435 var hours = this.time.getHours();
15436 var minutes = this.time.getMinutes();
15449 hours = hours - 12;
15453 hours = '0' + hours;
15457 minutes = '0' + minutes;
15460 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15461 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15462 this.pop.select('button', true).first().dom.innerHTML = period;
15468 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15470 var cls = ['bottom'];
15472 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15479 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15484 this.picker().addClass(cls.join('-'));
15488 Roo.each(cls, function(c){
15490 _this.picker().setTop(_this.inputEl().getHeight());
15494 _this.picker().setTop(0 - _this.picker().getHeight());
15499 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15503 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15510 onFocus : function()
15512 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15516 onBlur : function()
15518 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15524 this.picker().show();
15529 this.fireEvent('show', this, this.date);
15534 this.picker().hide();
15537 this.fireEvent('hide', this, this.date);
15540 setTime : function()
15543 this.setValue(this.time.format(this.format));
15545 this.fireEvent('select', this, this.date);
15550 onMousedown: function(e){
15551 e.stopPropagation();
15552 e.preventDefault();
15555 onIncrementHours: function()
15557 Roo.log('onIncrementHours');
15558 this.time = this.time.add(Date.HOUR, 1);
15563 onDecrementHours: function()
15565 Roo.log('onDecrementHours');
15566 this.time = this.time.add(Date.HOUR, -1);
15570 onIncrementMinutes: function()
15572 Roo.log('onIncrementMinutes');
15573 this.time = this.time.add(Date.MINUTE, 1);
15577 onDecrementMinutes: function()
15579 Roo.log('onDecrementMinutes');
15580 this.time = this.time.add(Date.MINUTE, -1);
15584 onTogglePeriod: function()
15586 Roo.log('onTogglePeriod');
15587 this.time = this.time.add(Date.HOUR, 12);
15594 Roo.apply(Roo.bootstrap.TimeField, {
15624 cls: 'btn btn-info ok',
15636 Roo.apply(Roo.bootstrap.TimeField, {
15640 cls: 'datepicker dropdown-menu',
15644 cls: 'datepicker-time',
15648 cls: 'table-condensed',
15650 Roo.bootstrap.TimeField.content,
15651 Roo.bootstrap.TimeField.footer
15670 * @class Roo.bootstrap.CheckBox
15671 * @extends Roo.bootstrap.Input
15672 * Bootstrap CheckBox class
15674 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15675 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15676 * @cfg {String} boxLabel The text that appears beside the checkbox
15677 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15678 * @cfg {Boolean} checked initnal the element
15682 * Create a new CheckBox
15683 * @param {Object} config The config object
15686 Roo.bootstrap.CheckBox = function(config){
15687 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15692 * Fires when the element is checked or unchecked.
15693 * @param {Roo.bootstrap.CheckBox} this This input
15694 * @param {Boolean} checked The new checked value
15700 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15702 inputType: 'checkbox',
15709 getAutoCreate : function()
15711 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15717 cfg.cls = 'form-group checkbox' //input-group
15725 type : this.inputType,
15726 value : (!this.checked) ? this.valueOff : this.inputValue,
15727 cls : 'roo-checkbox', //'form-box',
15728 placeholder : this.placeholder || ''
15732 if (this.weight) { // Validity check?
15733 cfg.cls += " checkbox-" + this.weight;
15736 if (this.disabled) {
15737 input.disabled=true;
15741 input.checked = this.checked;
15745 input.name = this.name;
15749 input.cls += ' input-' + this.size;
15753 ['xs','sm','md','lg'].map(function(size){
15754 if (settings[size]) {
15755 cfg.cls += ' col-' + size + '-' + settings[size];
15761 var inputblock = input;
15766 if (this.before || this.after) {
15769 cls : 'input-group',
15773 inputblock.cn.push({
15775 cls : 'input-group-addon',
15779 inputblock.cn.push(input);
15781 inputblock.cn.push({
15783 cls : 'input-group-addon',
15790 if (align ==='left' && this.fieldLabel.length) {
15791 Roo.log("left and has label");
15797 cls : 'control-label col-md-' + this.labelWidth,
15798 html : this.fieldLabel
15802 cls : "col-md-" + (12 - this.labelWidth),
15809 } else if ( this.fieldLabel.length) {
15814 tag: this.boxLabel ? 'span' : 'label',
15816 cls: 'control-label box-input-label',
15817 //cls : 'input-group-addon',
15818 html : this.fieldLabel
15828 Roo.log(" no label && no align");
15829 cfg.cn = [ inputblock ] ;
15838 html: this.boxLabel
15850 * return the real input element.
15852 inputEl: function ()
15854 return this.el.select('input.roo-checkbox',true).first();
15859 return this.el.select('label.control-label',true).first();
15862 initEvents : function()
15864 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15866 this.inputEl().on('click', this.onClick, this);
15870 onClick : function()
15872 this.setChecked(!this.checked);
15875 setChecked : function(state,suppressEvent)
15877 this.checked = state;
15879 this.inputEl().dom.checked = state;
15881 if(suppressEvent !== true){
15882 this.fireEvent('check', this, state);
15885 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15889 setValue : function(v,suppressEvent)
15891 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15905 * @class Roo.bootstrap.Radio
15906 * @extends Roo.bootstrap.CheckBox
15907 * Bootstrap Radio class
15910 * Create a new Radio
15911 * @param {Object} config The config object
15914 Roo.bootstrap.Radio = function(config){
15915 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15919 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15921 inputType: 'radio',
15925 getAutoCreate : function()
15927 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15933 cfg.cls = 'form-group radio' //input-group
15938 type : this.inputType,
15939 value : (!this.checked) ? this.valueOff : this.inputValue,
15941 placeholder : this.placeholder || ''
15944 if (this.weight) { // Validity check?
15945 cfg.cls += " radio-" + this.weight;
15947 if (this.disabled) {
15948 input.disabled=true;
15952 input.checked = this.checked;
15956 input.name = this.name;
15960 input.cls += ' input-' + this.size;
15964 ['xs','sm','md','lg'].map(function(size){
15965 if (settings[size]) {
15966 cfg.cls += ' col-' + size + '-' + settings[size];
15970 var inputblock = input;
15972 if (this.before || this.after) {
15975 cls : 'input-group',
15979 inputblock.cn.push({
15981 cls : 'input-group-addon',
15985 inputblock.cn.push(input);
15987 inputblock.cn.push({
15989 cls : 'input-group-addon',
15996 if (align ==='left' && this.fieldLabel.length) {
15997 Roo.log("left and has label");
16003 cls : 'control-label col-md-' + this.labelWidth,
16004 html : this.fieldLabel
16008 cls : "col-md-" + (12 - this.labelWidth),
16015 } else if ( this.fieldLabel.length) {
16022 cls: 'control-label box-input-label',
16023 //cls : 'input-group-addon',
16024 html : this.fieldLabel
16034 Roo.log(" no label && no align");
16049 html: this.boxLabel
16056 inputEl: function ()
16058 return this.el.select('input.roo-radio',true).first();
16060 onClick : function()
16062 this.setChecked(true);
16065 setChecked : function(state,suppressEvent)
16068 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16069 v.dom.checked = false;
16073 this.checked = state;
16074 this.inputEl().dom.checked = state;
16076 if(suppressEvent !== true){
16077 this.fireEvent('check', this, state);
16080 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16084 getGroupValue : function()
16087 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16088 if(v.dom.checked == true){
16089 value = v.dom.value;
16097 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16098 * @return {Mixed} value The field value
16100 getValue : function(){
16101 return this.getGroupValue();
16107 //<script type="text/javascript">
16110 * Based Ext JS Library 1.1.1
16111 * Copyright(c) 2006-2007, Ext JS, LLC.
16117 * @class Roo.HtmlEditorCore
16118 * @extends Roo.Component
16119 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16121 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16124 Roo.HtmlEditorCore = function(config){
16127 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16130 * @event initialize
16131 * Fires when the editor is fully initialized (including the iframe)
16132 * @param {Roo.HtmlEditorCore} this
16137 * Fires when the editor is first receives the focus. Any insertion must wait
16138 * until after this event.
16139 * @param {Roo.HtmlEditorCore} this
16143 * @event beforesync
16144 * Fires before the textarea is updated with content from the editor iframe. Return false
16145 * to cancel the sync.
16146 * @param {Roo.HtmlEditorCore} this
16147 * @param {String} html
16151 * @event beforepush
16152 * Fires before the iframe editor is updated with content from the textarea. Return false
16153 * to cancel the push.
16154 * @param {Roo.HtmlEditorCore} this
16155 * @param {String} html
16160 * Fires when the textarea is updated with content from the editor iframe.
16161 * @param {Roo.HtmlEditorCore} this
16162 * @param {String} html
16167 * Fires when the iframe editor is updated with content from the textarea.
16168 * @param {Roo.HtmlEditorCore} this
16169 * @param {String} html
16174 * @event editorevent
16175 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16176 * @param {Roo.HtmlEditorCore} this
16184 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16188 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16194 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16199 * @cfg {Number} height (in pixels)
16203 * @cfg {Number} width (in pixels)
16208 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16211 stylesheets: false,
16216 // private properties
16217 validationEvent : false,
16219 initialized : false,
16221 sourceEditMode : false,
16222 onFocus : Roo.emptyFn,
16224 hideMode:'offsets',
16232 * Protected method that will not generally be called directly. It
16233 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16234 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16236 getDocMarkup : function(){
16239 Roo.log(this.stylesheets);
16241 // inherit styels from page...??
16242 if (this.stylesheets === false) {
16244 Roo.get(document.head).select('style').each(function(node) {
16245 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16248 Roo.get(document.head).select('link').each(function(node) {
16249 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16252 } else if (!this.stylesheets.length) {
16254 st = '<style type="text/css">' +
16255 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16258 Roo.each(this.stylesheets, function(s) {
16259 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16264 st += '<style type="text/css">' +
16265 'IMG { cursor: pointer } ' +
16269 return '<html><head>' + st +
16270 //<style type="text/css">' +
16271 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16273 ' </head><body class="roo-htmleditor-body"></body></html>';
16277 onRender : function(ct, position)
16280 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16281 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16284 this.el.dom.style.border = '0 none';
16285 this.el.dom.setAttribute('tabIndex', -1);
16286 this.el.addClass('x-hidden hide');
16290 if(Roo.isIE){ // fix IE 1px bogus margin
16291 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16295 this.frameId = Roo.id();
16299 var iframe = this.owner.wrap.createChild({
16301 cls: 'form-control', // bootstrap..
16303 name: this.frameId,
16304 frameBorder : 'no',
16305 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16310 this.iframe = iframe.dom;
16312 this.assignDocWin();
16314 this.doc.designMode = 'on';
16317 this.doc.write(this.getDocMarkup());
16321 var task = { // must defer to wait for browser to be ready
16323 //console.log("run task?" + this.doc.readyState);
16324 this.assignDocWin();
16325 if(this.doc.body || this.doc.readyState == 'complete'){
16327 this.doc.designMode="on";
16331 Roo.TaskMgr.stop(task);
16332 this.initEditor.defer(10, this);
16339 Roo.TaskMgr.start(task);
16346 onResize : function(w, h)
16348 Roo.log('resize: ' +w + ',' + h );
16349 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16353 if(typeof w == 'number'){
16355 this.iframe.style.width = w + 'px';
16357 if(typeof h == 'number'){
16359 this.iframe.style.height = h + 'px';
16361 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16368 * Toggles the editor between standard and source edit mode.
16369 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16371 toggleSourceEdit : function(sourceEditMode){
16373 this.sourceEditMode = sourceEditMode === true;
16375 if(this.sourceEditMode){
16377 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16380 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16381 //this.iframe.className = '';
16384 //this.setSize(this.owner.wrap.getSize());
16385 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16392 * Protected method that will not generally be called directly. If you need/want
16393 * custom HTML cleanup, this is the method you should override.
16394 * @param {String} html The HTML to be cleaned
16395 * return {String} The cleaned HTML
16397 cleanHtml : function(html){
16398 html = String(html);
16399 if(html.length > 5){
16400 if(Roo.isSafari){ // strip safari nonsense
16401 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16404 if(html == ' '){
16411 * HTML Editor -> Textarea
16412 * Protected method that will not generally be called directly. Syncs the contents
16413 * of the editor iframe with the textarea.
16415 syncValue : function(){
16416 if(this.initialized){
16417 var bd = (this.doc.body || this.doc.documentElement);
16418 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16419 var html = bd.innerHTML;
16421 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16422 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16424 html = '<div style="'+m[0]+'">' + html + '</div>';
16427 html = this.cleanHtml(html);
16428 // fix up the special chars.. normaly like back quotes in word...
16429 // however we do not want to do this with chinese..
16430 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16431 var cc = b.charCodeAt();
16433 (cc >= 0x4E00 && cc < 0xA000 ) ||
16434 (cc >= 0x3400 && cc < 0x4E00 ) ||
16435 (cc >= 0xf900 && cc < 0xfb00 )
16441 if(this.owner.fireEvent('beforesync', this, html) !== false){
16442 this.el.dom.value = html;
16443 this.owner.fireEvent('sync', this, html);
16449 * Protected method that will not generally be called directly. Pushes the value of the textarea
16450 * into the iframe editor.
16452 pushValue : function(){
16453 if(this.initialized){
16454 var v = this.el.dom.value.trim();
16456 // if(v.length < 1){
16460 if(this.owner.fireEvent('beforepush', this, v) !== false){
16461 var d = (this.doc.body || this.doc.documentElement);
16463 this.cleanUpPaste();
16464 this.el.dom.value = d.innerHTML;
16465 this.owner.fireEvent('push', this, v);
16471 deferFocus : function(){
16472 this.focus.defer(10, this);
16476 focus : function(){
16477 if(this.win && !this.sourceEditMode){
16484 assignDocWin: function()
16486 var iframe = this.iframe;
16489 this.doc = iframe.contentWindow.document;
16490 this.win = iframe.contentWindow;
16492 if (!Roo.get(this.frameId)) {
16495 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16496 this.win = Roo.get(this.frameId).dom.contentWindow;
16501 initEditor : function(){
16502 //console.log("INIT EDITOR");
16503 this.assignDocWin();
16507 this.doc.designMode="on";
16509 this.doc.write(this.getDocMarkup());
16512 var dbody = (this.doc.body || this.doc.documentElement);
16513 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16514 // this copies styles from the containing element into thsi one..
16515 // not sure why we need all of this..
16516 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16518 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16519 //ss['background-attachment'] = 'fixed'; // w3c
16520 dbody.bgProperties = 'fixed'; // ie
16521 //Roo.DomHelper.applyStyles(dbody, ss);
16522 Roo.EventManager.on(this.doc, {
16523 //'mousedown': this.onEditorEvent,
16524 'mouseup': this.onEditorEvent,
16525 'dblclick': this.onEditorEvent,
16526 'click': this.onEditorEvent,
16527 'keyup': this.onEditorEvent,
16532 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16534 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16535 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16537 this.initialized = true;
16539 this.owner.fireEvent('initialize', this);
16544 onDestroy : function(){
16550 //for (var i =0; i < this.toolbars.length;i++) {
16551 // // fixme - ask toolbars for heights?
16552 // this.toolbars[i].onDestroy();
16555 //this.wrap.dom.innerHTML = '';
16556 //this.wrap.remove();
16561 onFirstFocus : function(){
16563 this.assignDocWin();
16566 this.activated = true;
16569 if(Roo.isGecko){ // prevent silly gecko errors
16571 var s = this.win.getSelection();
16572 if(!s.focusNode || s.focusNode.nodeType != 3){
16573 var r = s.getRangeAt(0);
16574 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16579 this.execCmd('useCSS', true);
16580 this.execCmd('styleWithCSS', false);
16583 this.owner.fireEvent('activate', this);
16587 adjustFont: function(btn){
16588 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16589 //if(Roo.isSafari){ // safari
16592 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16593 if(Roo.isSafari){ // safari
16594 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16595 v = (v < 10) ? 10 : v;
16596 v = (v > 48) ? 48 : v;
16597 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16602 v = Math.max(1, v+adjust);
16604 this.execCmd('FontSize', v );
16607 onEditorEvent : function(e){
16608 this.owner.fireEvent('editorevent', this, e);
16609 // this.updateToolbar();
16610 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16613 insertTag : function(tg)
16615 // could be a bit smarter... -> wrap the current selected tRoo..
16616 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16618 range = this.createRange(this.getSelection());
16619 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16620 wrappingNode.appendChild(range.extractContents());
16621 range.insertNode(wrappingNode);
16628 this.execCmd("formatblock", tg);
16632 insertText : function(txt)
16636 var range = this.createRange();
16637 range.deleteContents();
16638 //alert(Sender.getAttribute('label'));
16640 range.insertNode(this.doc.createTextNode(txt));
16646 * Executes a Midas editor command on the editor document and performs necessary focus and
16647 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16648 * @param {String} cmd The Midas command
16649 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16651 relayCmd : function(cmd, value){
16653 this.execCmd(cmd, value);
16654 this.owner.fireEvent('editorevent', this);
16655 //this.updateToolbar();
16656 this.owner.deferFocus();
16660 * Executes a Midas editor command directly on the editor document.
16661 * For visual commands, you should use {@link #relayCmd} instead.
16662 * <b>This should only be called after the editor is initialized.</b>
16663 * @param {String} cmd The Midas command
16664 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16666 execCmd : function(cmd, value){
16667 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16674 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16676 * @param {String} text | dom node..
16678 insertAtCursor : function(text)
16683 if(!this.activated){
16689 var r = this.doc.selection.createRange();
16700 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16704 // from jquery ui (MIT licenced)
16706 var win = this.win;
16708 if (win.getSelection && win.getSelection().getRangeAt) {
16709 range = win.getSelection().getRangeAt(0);
16710 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16711 range.insertNode(node);
16712 } else if (win.document.selection && win.document.selection.createRange) {
16713 // no firefox support
16714 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16715 win.document.selection.createRange().pasteHTML(txt);
16717 // no firefox support
16718 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16719 this.execCmd('InsertHTML', txt);
16728 mozKeyPress : function(e){
16730 var c = e.getCharCode(), cmd;
16733 c = String.fromCharCode(c).toLowerCase();
16747 this.cleanUpPaste.defer(100, this);
16755 e.preventDefault();
16763 fixKeys : function(){ // load time branching for fastest keydown performance
16765 return function(e){
16766 var k = e.getKey(), r;
16769 r = this.doc.selection.createRange();
16772 r.pasteHTML('    ');
16779 r = this.doc.selection.createRange();
16781 var target = r.parentElement();
16782 if(!target || target.tagName.toLowerCase() != 'li'){
16784 r.pasteHTML('<br />');
16790 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16791 this.cleanUpPaste.defer(100, this);
16797 }else if(Roo.isOpera){
16798 return function(e){
16799 var k = e.getKey();
16803 this.execCmd('InsertHTML','    ');
16806 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16807 this.cleanUpPaste.defer(100, this);
16812 }else if(Roo.isSafari){
16813 return function(e){
16814 var k = e.getKey();
16818 this.execCmd('InsertText','\t');
16822 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16823 this.cleanUpPaste.defer(100, this);
16831 getAllAncestors: function()
16833 var p = this.getSelectedNode();
16836 a.push(p); // push blank onto stack..
16837 p = this.getParentElement();
16841 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16845 a.push(this.doc.body);
16849 lastSelNode : false,
16852 getSelection : function()
16854 this.assignDocWin();
16855 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16858 getSelectedNode: function()
16860 // this may only work on Gecko!!!
16862 // should we cache this!!!!
16867 var range = this.createRange(this.getSelection()).cloneRange();
16870 var parent = range.parentElement();
16872 var testRange = range.duplicate();
16873 testRange.moveToElementText(parent);
16874 if (testRange.inRange(range)) {
16877 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16880 parent = parent.parentElement;
16885 // is ancestor a text element.
16886 var ac = range.commonAncestorContainer;
16887 if (ac.nodeType == 3) {
16888 ac = ac.parentNode;
16891 var ar = ac.childNodes;
16894 var other_nodes = [];
16895 var has_other_nodes = false;
16896 for (var i=0;i<ar.length;i++) {
16897 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16900 // fullly contained node.
16902 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16907 // probably selected..
16908 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16909 other_nodes.push(ar[i]);
16913 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16918 has_other_nodes = true;
16920 if (!nodes.length && other_nodes.length) {
16921 nodes= other_nodes;
16923 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16929 createRange: function(sel)
16931 // this has strange effects when using with
16932 // top toolbar - not sure if it's a great idea.
16933 //this.editor.contentWindow.focus();
16934 if (typeof sel != "undefined") {
16936 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16938 return this.doc.createRange();
16941 return this.doc.createRange();
16944 getParentElement: function()
16947 this.assignDocWin();
16948 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16950 var range = this.createRange(sel);
16953 var p = range.commonAncestorContainer;
16954 while (p.nodeType == 3) { // text node
16965 * Range intersection.. the hard stuff...
16969 * [ -- selected range --- ]
16973 * if end is before start or hits it. fail.
16974 * if start is after end or hits it fail.
16976 * if either hits (but other is outside. - then it's not
16982 // @see http://www.thismuchiknow.co.uk/?p=64.
16983 rangeIntersectsNode : function(range, node)
16985 var nodeRange = node.ownerDocument.createRange();
16987 nodeRange.selectNode(node);
16989 nodeRange.selectNodeContents(node);
16992 var rangeStartRange = range.cloneRange();
16993 rangeStartRange.collapse(true);
16995 var rangeEndRange = range.cloneRange();
16996 rangeEndRange.collapse(false);
16998 var nodeStartRange = nodeRange.cloneRange();
16999 nodeStartRange.collapse(true);
17001 var nodeEndRange = nodeRange.cloneRange();
17002 nodeEndRange.collapse(false);
17004 return rangeStartRange.compareBoundaryPoints(
17005 Range.START_TO_START, nodeEndRange) == -1 &&
17006 rangeEndRange.compareBoundaryPoints(
17007 Range.START_TO_START, nodeStartRange) == 1;
17011 rangeCompareNode : function(range, node)
17013 var nodeRange = node.ownerDocument.createRange();
17015 nodeRange.selectNode(node);
17017 nodeRange.selectNodeContents(node);
17021 range.collapse(true);
17023 nodeRange.collapse(true);
17025 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17026 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17028 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17030 var nodeIsBefore = ss == 1;
17031 var nodeIsAfter = ee == -1;
17033 if (nodeIsBefore && nodeIsAfter)
17035 if (!nodeIsBefore && nodeIsAfter)
17036 return 1; //right trailed.
17038 if (nodeIsBefore && !nodeIsAfter)
17039 return 2; // left trailed.
17044 // private? - in a new class?
17045 cleanUpPaste : function()
17047 // cleans up the whole document..
17048 Roo.log('cleanuppaste');
17050 this.cleanUpChildren(this.doc.body);
17051 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17052 if (clean != this.doc.body.innerHTML) {
17053 this.doc.body.innerHTML = clean;
17058 cleanWordChars : function(input) {// change the chars to hex code
17059 var he = Roo.HtmlEditorCore;
17061 var output = input;
17062 Roo.each(he.swapCodes, function(sw) {
17063 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17065 output = output.replace(swapper, sw[1]);
17072 cleanUpChildren : function (n)
17074 if (!n.childNodes.length) {
17077 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17078 this.cleanUpChild(n.childNodes[i]);
17085 cleanUpChild : function (node)
17088 //console.log(node);
17089 if (node.nodeName == "#text") {
17090 // clean up silly Windows -- stuff?
17093 if (node.nodeName == "#comment") {
17094 node.parentNode.removeChild(node);
17095 // clean up silly Windows -- stuff?
17099 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17101 node.parentNode.removeChild(node);
17106 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17108 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17109 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17111 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17112 // remove_keep_children = true;
17115 if (remove_keep_children) {
17116 this.cleanUpChildren(node);
17117 // inserts everything just before this node...
17118 while (node.childNodes.length) {
17119 var cn = node.childNodes[0];
17120 node.removeChild(cn);
17121 node.parentNode.insertBefore(cn, node);
17123 node.parentNode.removeChild(node);
17127 if (!node.attributes || !node.attributes.length) {
17128 this.cleanUpChildren(node);
17132 function cleanAttr(n,v)
17135 if (v.match(/^\./) || v.match(/^\//)) {
17138 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17141 if (v.match(/^#/)) {
17144 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17145 node.removeAttribute(n);
17149 function cleanStyle(n,v)
17151 if (v.match(/expression/)) { //XSS?? should we even bother..
17152 node.removeAttribute(n);
17155 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17156 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17159 var parts = v.split(/;/);
17162 Roo.each(parts, function(p) {
17163 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17167 var l = p.split(':').shift().replace(/\s+/g,'');
17168 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17170 if ( cblack.indexOf(l) > -1) {
17171 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17172 //node.removeAttribute(n);
17176 // only allow 'c whitelisted system attributes'
17177 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17178 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17179 //node.removeAttribute(n);
17189 if (clean.length) {
17190 node.setAttribute(n, clean.join(';'));
17192 node.removeAttribute(n);
17198 for (var i = node.attributes.length-1; i > -1 ; i--) {
17199 var a = node.attributes[i];
17202 if (a.name.toLowerCase().substr(0,2)=='on') {
17203 node.removeAttribute(a.name);
17206 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17207 node.removeAttribute(a.name);
17210 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17211 cleanAttr(a.name,a.value); // fixme..
17214 if (a.name == 'style') {
17215 cleanStyle(a.name,a.value);
17218 /// clean up MS crap..
17219 // tecnically this should be a list of valid class'es..
17222 if (a.name == 'class') {
17223 if (a.value.match(/^Mso/)) {
17224 node.className = '';
17227 if (a.value.match(/body/)) {
17228 node.className = '';
17239 this.cleanUpChildren(node);
17244 * Clean up MS wordisms...
17246 cleanWord : function(node)
17249 var cleanWordChildren = function()
17251 if (!node.childNodes.length) {
17254 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17255 _t.cleanWord(node.childNodes[i]);
17261 this.cleanWord(this.doc.body);
17264 if (node.nodeName == "#text") {
17265 // clean up silly Windows -- stuff?
17268 if (node.nodeName == "#comment") {
17269 node.parentNode.removeChild(node);
17270 // clean up silly Windows -- stuff?
17274 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17275 node.parentNode.removeChild(node);
17279 // remove - but keep children..
17280 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17281 while (node.childNodes.length) {
17282 var cn = node.childNodes[0];
17283 node.removeChild(cn);
17284 node.parentNode.insertBefore(cn, node);
17286 node.parentNode.removeChild(node);
17287 cleanWordChildren();
17291 if (node.className.length) {
17293 var cn = node.className.split(/\W+/);
17295 Roo.each(cn, function(cls) {
17296 if (cls.match(/Mso[a-zA-Z]+/)) {
17301 node.className = cna.length ? cna.join(' ') : '';
17303 node.removeAttribute("class");
17307 if (node.hasAttribute("lang")) {
17308 node.removeAttribute("lang");
17311 if (node.hasAttribute("style")) {
17313 var styles = node.getAttribute("style").split(";");
17315 Roo.each(styles, function(s) {
17316 if (!s.match(/:/)) {
17319 var kv = s.split(":");
17320 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17323 // what ever is left... we allow.
17326 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17327 if (!nstyle.length) {
17328 node.removeAttribute('style');
17332 cleanWordChildren();
17336 domToHTML : function(currentElement, depth, nopadtext) {
17338 depth = depth || 0;
17339 nopadtext = nopadtext || false;
17341 if (!currentElement) {
17342 return this.domToHTML(this.doc.body);
17345 //Roo.log(currentElement);
17347 var allText = false;
17348 var nodeName = currentElement.nodeName;
17349 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17351 if (nodeName == '#text') {
17352 return currentElement.nodeValue;
17357 if (nodeName != 'BODY') {
17360 // Prints the node tagName, such as <A>, <IMG>, etc
17363 for(i = 0; i < currentElement.attributes.length;i++) {
17365 var aname = currentElement.attributes.item(i).name;
17366 if (!currentElement.attributes.item(i).value.length) {
17369 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17372 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17381 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17384 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17389 // Traverse the tree
17391 var currentElementChild = currentElement.childNodes.item(i);
17392 var allText = true;
17393 var innerHTML = '';
17395 while (currentElementChild) {
17396 // Formatting code (indent the tree so it looks nice on the screen)
17397 var nopad = nopadtext;
17398 if (lastnode == 'SPAN') {
17402 if (currentElementChild.nodeName == '#text') {
17403 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17404 if (!nopad && toadd.length > 80) {
17405 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17407 innerHTML += toadd;
17410 currentElementChild = currentElement.childNodes.item(i);
17416 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17418 // Recursively traverse the tree structure of the child node
17419 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17420 lastnode = currentElementChild.nodeName;
17422 currentElementChild=currentElement.childNodes.item(i);
17428 // The remaining code is mostly for formatting the tree
17429 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17434 ret+= "</"+tagName+">";
17440 // hide stuff that is not compatible
17454 * @event specialkey
17458 * @cfg {String} fieldClass @hide
17461 * @cfg {String} focusClass @hide
17464 * @cfg {String} autoCreate @hide
17467 * @cfg {String} inputType @hide
17470 * @cfg {String} invalidClass @hide
17473 * @cfg {String} invalidText @hide
17476 * @cfg {String} msgFx @hide
17479 * @cfg {String} validateOnBlur @hide
17483 Roo.HtmlEditorCore.white = [
17484 'area', 'br', 'img', 'input', 'hr', 'wbr',
17486 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17487 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17488 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17489 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17490 'table', 'ul', 'xmp',
17492 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17495 'dir', 'menu', 'ol', 'ul', 'dl',
17501 Roo.HtmlEditorCore.black = [
17502 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17504 'base', 'basefont', 'bgsound', 'blink', 'body',
17505 'frame', 'frameset', 'head', 'html', 'ilayer',
17506 'iframe', 'layer', 'link', 'meta', 'object',
17507 'script', 'style' ,'title', 'xml' // clean later..
17509 Roo.HtmlEditorCore.clean = [
17510 'script', 'style', 'title', 'xml'
17512 Roo.HtmlEditorCore.remove = [
17517 Roo.HtmlEditorCore.ablack = [
17521 Roo.HtmlEditorCore.aclean = [
17522 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17526 Roo.HtmlEditorCore.pwhite= [
17527 'http', 'https', 'mailto'
17530 // white listed style attributes.
17531 Roo.HtmlEditorCore.cwhite= [
17532 // 'text-align', /// default is to allow most things..
17538 // black listed style attributes.
17539 Roo.HtmlEditorCore.cblack= [
17540 // 'font-size' -- this can be set by the project
17544 Roo.HtmlEditorCore.swapCodes =[
17563 * @class Roo.bootstrap.HtmlEditor
17564 * @extends Roo.bootstrap.TextArea
17565 * Bootstrap HtmlEditor class
17568 * Create a new HtmlEditor
17569 * @param {Object} config The config object
17572 Roo.bootstrap.HtmlEditor = function(config){
17573 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17574 if (!this.toolbars) {
17575 this.toolbars = [];
17577 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17580 * @event initialize
17581 * Fires when the editor is fully initialized (including the iframe)
17582 * @param {HtmlEditor} this
17587 * Fires when the editor is first receives the focus. Any insertion must wait
17588 * until after this event.
17589 * @param {HtmlEditor} this
17593 * @event beforesync
17594 * Fires before the textarea is updated with content from the editor iframe. Return false
17595 * to cancel the sync.
17596 * @param {HtmlEditor} this
17597 * @param {String} html
17601 * @event beforepush
17602 * Fires before the iframe editor is updated with content from the textarea. Return false
17603 * to cancel the push.
17604 * @param {HtmlEditor} this
17605 * @param {String} html
17610 * Fires when the textarea is updated with content from the editor iframe.
17611 * @param {HtmlEditor} this
17612 * @param {String} html
17617 * Fires when the iframe editor is updated with content from the textarea.
17618 * @param {HtmlEditor} this
17619 * @param {String} html
17623 * @event editmodechange
17624 * Fires when the editor switches edit modes
17625 * @param {HtmlEditor} this
17626 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17628 editmodechange: true,
17630 * @event editorevent
17631 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17632 * @param {HtmlEditor} this
17636 * @event firstfocus
17637 * Fires when on first focus - needed by toolbars..
17638 * @param {HtmlEditor} this
17643 * Auto save the htmlEditor value as a file into Events
17644 * @param {HtmlEditor} this
17648 * @event savedpreview
17649 * preview the saved version of htmlEditor
17650 * @param {HtmlEditor} this
17657 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17661 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17666 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17671 * @cfg {Number} height (in pixels)
17675 * @cfg {Number} width (in pixels)
17680 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17683 stylesheets: false,
17688 // private properties
17689 validationEvent : false,
17691 initialized : false,
17694 onFocus : Roo.emptyFn,
17696 hideMode:'offsets',
17699 tbContainer : false,
17701 toolbarContainer :function() {
17702 return this.wrap.select('.x-html-editor-tb',true).first();
17706 * Protected method that will not generally be called directly. It
17707 * is called when the editor creates its toolbar. Override this method if you need to
17708 * add custom toolbar buttons.
17709 * @param {HtmlEditor} editor
17711 createToolbar : function(){
17713 Roo.log("create toolbars");
17715 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17716 this.toolbars[0].render(this.toolbarContainer());
17720 // if (!editor.toolbars || !editor.toolbars.length) {
17721 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17724 // for (var i =0 ; i < editor.toolbars.length;i++) {
17725 // editor.toolbars[i] = Roo.factory(
17726 // typeof(editor.toolbars[i]) == 'string' ?
17727 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17728 // Roo.bootstrap.HtmlEditor);
17729 // editor.toolbars[i].init(editor);
17735 onRender : function(ct, position)
17737 // Roo.log("Call onRender: " + this.xtype);
17739 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17741 this.wrap = this.inputEl().wrap({
17742 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17745 this.editorcore.onRender(ct, position);
17747 if (this.resizable) {
17748 this.resizeEl = new Roo.Resizable(this.wrap, {
17752 minHeight : this.height,
17753 height: this.height,
17754 handles : this.resizable,
17757 resize : function(r, w, h) {
17758 _t.onResize(w,h); // -something
17764 this.createToolbar(this);
17767 if(!this.width && this.resizable){
17768 this.setSize(this.wrap.getSize());
17770 if (this.resizeEl) {
17771 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17772 // should trigger onReize..
17778 onResize : function(w, h)
17780 Roo.log('resize: ' +w + ',' + h );
17781 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17785 if(this.inputEl() ){
17786 if(typeof w == 'number'){
17787 var aw = w - this.wrap.getFrameWidth('lr');
17788 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17791 if(typeof h == 'number'){
17792 var tbh = -11; // fixme it needs to tool bar size!
17793 for (var i =0; i < this.toolbars.length;i++) {
17794 // fixme - ask toolbars for heights?
17795 tbh += this.toolbars[i].el.getHeight();
17796 //if (this.toolbars[i].footer) {
17797 // tbh += this.toolbars[i].footer.el.getHeight();
17805 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17806 ah -= 5; // knock a few pixes off for look..
17807 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17811 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17812 this.editorcore.onResize(ew,eh);
17817 * Toggles the editor between standard and source edit mode.
17818 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17820 toggleSourceEdit : function(sourceEditMode)
17822 this.editorcore.toggleSourceEdit(sourceEditMode);
17824 if(this.editorcore.sourceEditMode){
17825 Roo.log('editor - showing textarea');
17828 // Roo.log(this.syncValue());
17830 this.inputEl().removeClass(['hide', 'x-hidden']);
17831 this.inputEl().dom.removeAttribute('tabIndex');
17832 this.inputEl().focus();
17834 Roo.log('editor - hiding textarea');
17836 // Roo.log(this.pushValue());
17839 this.inputEl().addClass(['hide', 'x-hidden']);
17840 this.inputEl().dom.setAttribute('tabIndex', -1);
17841 //this.deferFocus();
17844 if(this.resizable){
17845 this.setSize(this.wrap.getSize());
17848 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17851 // private (for BoxComponent)
17852 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17854 // private (for BoxComponent)
17855 getResizeEl : function(){
17859 // private (for BoxComponent)
17860 getPositionEl : function(){
17865 initEvents : function(){
17866 this.originalValue = this.getValue();
17870 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17873 // markInvalid : Roo.emptyFn,
17875 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17878 // clearInvalid : Roo.emptyFn,
17880 setValue : function(v){
17881 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17882 this.editorcore.pushValue();
17887 deferFocus : function(){
17888 this.focus.defer(10, this);
17892 focus : function(){
17893 this.editorcore.focus();
17899 onDestroy : function(){
17905 for (var i =0; i < this.toolbars.length;i++) {
17906 // fixme - ask toolbars for heights?
17907 this.toolbars[i].onDestroy();
17910 this.wrap.dom.innerHTML = '';
17911 this.wrap.remove();
17916 onFirstFocus : function(){
17917 //Roo.log("onFirstFocus");
17918 this.editorcore.onFirstFocus();
17919 for (var i =0; i < this.toolbars.length;i++) {
17920 this.toolbars[i].onFirstFocus();
17926 syncValue : function()
17928 this.editorcore.syncValue();
17931 pushValue : function()
17933 this.editorcore.pushValue();
17937 // hide stuff that is not compatible
17951 * @event specialkey
17955 * @cfg {String} fieldClass @hide
17958 * @cfg {String} focusClass @hide
17961 * @cfg {String} autoCreate @hide
17964 * @cfg {String} inputType @hide
17967 * @cfg {String} invalidClass @hide
17970 * @cfg {String} invalidText @hide
17973 * @cfg {String} msgFx @hide
17976 * @cfg {String} validateOnBlur @hide
17985 Roo.namespace('Roo.bootstrap.htmleditor');
17987 * @class Roo.bootstrap.HtmlEditorToolbar1
17992 new Roo.bootstrap.HtmlEditor({
17995 new Roo.bootstrap.HtmlEditorToolbar1({
17996 disable : { fonts: 1 , format: 1, ..., ... , ...],
18002 * @cfg {Object} disable List of elements to disable..
18003 * @cfg {Array} btns List of additional buttons.
18007 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18010 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18013 Roo.apply(this, config);
18015 // default disabled, based on 'good practice'..
18016 this.disable = this.disable || {};
18017 Roo.applyIf(this.disable, {
18020 specialElements : true
18022 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18024 this.editor = config.editor;
18025 this.editorcore = config.editor.editorcore;
18027 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18029 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18030 // dont call parent... till later.
18032 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18037 editorcore : false,
18042 "h1","h2","h3","h4","h5","h6",
18044 "abbr", "acronym", "address", "cite", "samp", "var",
18048 onRender : function(ct, position)
18050 // Roo.log("Call onRender: " + this.xtype);
18052 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18054 this.el.dom.style.marginBottom = '0';
18056 var editorcore = this.editorcore;
18057 var editor= this.editor;
18060 var btn = function(id,cmd , toggle, handler){
18062 var event = toggle ? 'toggle' : 'click';
18067 xns: Roo.bootstrap,
18070 enableToggle:toggle !== false,
18072 pressed : toggle ? false : null,
18075 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18076 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18085 xns: Roo.bootstrap,
18086 glyphicon : 'font',
18090 xns: Roo.bootstrap,
18094 Roo.each(this.formats, function(f) {
18095 style.menu.items.push({
18097 xns: Roo.bootstrap,
18098 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18103 editorcore.insertTag(this.tagname);
18110 children.push(style);
18113 btn('bold',false,true);
18114 btn('italic',false,true);
18115 btn('align-left', 'justifyleft',true);
18116 btn('align-center', 'justifycenter',true);
18117 btn('align-right' , 'justifyright',true);
18118 btn('link', false, false, function(btn) {
18119 //Roo.log("create link?");
18120 var url = prompt(this.createLinkText, this.defaultLinkValue);
18121 if(url && url != 'http:/'+'/'){
18122 this.editorcore.relayCmd('createlink', url);
18125 btn('list','insertunorderedlist',true);
18126 btn('pencil', false,true, function(btn){
18129 this.toggleSourceEdit(btn.pressed);
18135 xns: Roo.bootstrap,
18140 xns: Roo.bootstrap,
18145 cog.menu.items.push({
18147 xns: Roo.bootstrap,
18148 html : Clean styles,
18153 editorcore.insertTag(this.tagname);
18162 this.xtype = 'NavSimplebar';
18164 for(var i=0;i< children.length;i++) {
18166 this.buttons.add(this.addxtypeChild(children[i]));
18170 editor.on('editorevent', this.updateToolbar, this);
18172 onBtnClick : function(id)
18174 this.editorcore.relayCmd(id);
18175 this.editorcore.focus();
18179 * Protected method that will not generally be called directly. It triggers
18180 * a toolbar update by reading the markup state of the current selection in the editor.
18182 updateToolbar: function(){
18184 if(!this.editorcore.activated){
18185 this.editor.onFirstFocus(); // is this neeed?
18189 var btns = this.buttons;
18190 var doc = this.editorcore.doc;
18191 btns.get('bold').setActive(doc.queryCommandState('bold'));
18192 btns.get('italic').setActive(doc.queryCommandState('italic'));
18193 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18195 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18196 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18197 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18199 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18200 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18203 var ans = this.editorcore.getAllAncestors();
18204 if (this.formatCombo) {
18207 var store = this.formatCombo.store;
18208 this.formatCombo.setValue("");
18209 for (var i =0; i < ans.length;i++) {
18210 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18212 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18220 // hides menus... - so this cant be on a menu...
18221 Roo.bootstrap.MenuMgr.hideAll();
18223 Roo.bootstrap.MenuMgr.hideAll();
18224 //this.editorsyncValue();
18226 onFirstFocus: function() {
18227 this.buttons.each(function(item){
18231 toggleSourceEdit : function(sourceEditMode){
18234 if(sourceEditMode){
18235 Roo.log("disabling buttons");
18236 this.buttons.each( function(item){
18237 if(item.cmd != 'pencil'){
18243 Roo.log("enabling buttons");
18244 if(this.editorcore.initialized){
18245 this.buttons.each( function(item){
18251 Roo.log("calling toggole on editor");
18252 // tell the editor that it's been pressed..
18253 this.editor.toggleSourceEdit(sourceEditMode);
18263 * @class Roo.bootstrap.Table.AbstractSelectionModel
18264 * @extends Roo.util.Observable
18265 * Abstract base class for grid SelectionModels. It provides the interface that should be
18266 * implemented by descendant classes. This class should not be directly instantiated.
18269 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18270 this.locked = false;
18271 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18275 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18276 /** @ignore Called by the grid automatically. Do not call directly. */
18277 init : function(grid){
18283 * Locks the selections.
18286 this.locked = true;
18290 * Unlocks the selections.
18292 unlock : function(){
18293 this.locked = false;
18297 * Returns true if the selections are locked.
18298 * @return {Boolean}
18300 isLocked : function(){
18301 return this.locked;
18305 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18306 * @class Roo.bootstrap.Table.RowSelectionModel
18307 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18308 * It supports multiple selections and keyboard selection/navigation.
18310 * @param {Object} config
18313 Roo.bootstrap.Table.RowSelectionModel = function(config){
18314 Roo.apply(this, config);
18315 this.selections = new Roo.util.MixedCollection(false, function(o){
18320 this.lastActive = false;
18324 * @event selectionchange
18325 * Fires when the selection changes
18326 * @param {SelectionModel} this
18328 "selectionchange" : true,
18330 * @event afterselectionchange
18331 * Fires after the selection changes (eg. by key press or clicking)
18332 * @param {SelectionModel} this
18334 "afterselectionchange" : true,
18336 * @event beforerowselect
18337 * Fires when a row is selected being selected, return false to cancel.
18338 * @param {SelectionModel} this
18339 * @param {Number} rowIndex The selected index
18340 * @param {Boolean} keepExisting False if other selections will be cleared
18342 "beforerowselect" : true,
18345 * Fires when a row is selected.
18346 * @param {SelectionModel} this
18347 * @param {Number} rowIndex The selected index
18348 * @param {Roo.data.Record} r The record
18350 "rowselect" : true,
18352 * @event rowdeselect
18353 * Fires when a row is deselected.
18354 * @param {SelectionModel} this
18355 * @param {Number} rowIndex The selected index
18357 "rowdeselect" : true
18359 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18360 this.locked = false;
18363 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18365 * @cfg {Boolean} singleSelect
18366 * True to allow selection of only one row at a time (defaults to false)
18368 singleSelect : false,
18371 initEvents : function(){
18373 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18374 this.grid.on("mousedown", this.handleMouseDown, this);
18375 }else{ // allow click to work like normal
18376 this.grid.on("rowclick", this.handleDragableRowClick, this);
18379 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18380 "up" : function(e){
18382 this.selectPrevious(e.shiftKey);
18383 }else if(this.last !== false && this.lastActive !== false){
18384 var last = this.last;
18385 this.selectRange(this.last, this.lastActive-1);
18386 this.grid.getView().focusRow(this.lastActive);
18387 if(last !== false){
18391 this.selectFirstRow();
18393 this.fireEvent("afterselectionchange", this);
18395 "down" : function(e){
18397 this.selectNext(e.shiftKey);
18398 }else if(this.last !== false && this.lastActive !== false){
18399 var last = this.last;
18400 this.selectRange(this.last, this.lastActive+1);
18401 this.grid.getView().focusRow(this.lastActive);
18402 if(last !== false){
18406 this.selectFirstRow();
18408 this.fireEvent("afterselectionchange", this);
18413 var view = this.grid.view;
18414 view.on("refresh", this.onRefresh, this);
18415 view.on("rowupdated", this.onRowUpdated, this);
18416 view.on("rowremoved", this.onRemove, this);
18420 onRefresh : function(){
18421 var ds = this.grid.dataSource, i, v = this.grid.view;
18422 var s = this.selections;
18423 s.each(function(r){
18424 if((i = ds.indexOfId(r.id)) != -1){
18433 onRemove : function(v, index, r){
18434 this.selections.remove(r);
18438 onRowUpdated : function(v, index, r){
18439 if(this.isSelected(r)){
18440 v.onRowSelect(index);
18446 * @param {Array} records The records to select
18447 * @param {Boolean} keepExisting (optional) True to keep existing selections
18449 selectRecords : function(records, keepExisting){
18451 this.clearSelections();
18453 var ds = this.grid.dataSource;
18454 for(var i = 0, len = records.length; i < len; i++){
18455 this.selectRow(ds.indexOf(records[i]), true);
18460 * Gets the number of selected rows.
18463 getCount : function(){
18464 return this.selections.length;
18468 * Selects the first row in the grid.
18470 selectFirstRow : function(){
18475 * Select the last row.
18476 * @param {Boolean} keepExisting (optional) True to keep existing selections
18478 selectLastRow : function(keepExisting){
18479 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18483 * Selects the row immediately following the last selected row.
18484 * @param {Boolean} keepExisting (optional) True to keep existing selections
18486 selectNext : function(keepExisting){
18487 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18488 this.selectRow(this.last+1, keepExisting);
18489 this.grid.getView().focusRow(this.last);
18494 * Selects the row that precedes the last selected row.
18495 * @param {Boolean} keepExisting (optional) True to keep existing selections
18497 selectPrevious : function(keepExisting){
18499 this.selectRow(this.last-1, keepExisting);
18500 this.grid.getView().focusRow(this.last);
18505 * Returns the selected records
18506 * @return {Array} Array of selected records
18508 getSelections : function(){
18509 return [].concat(this.selections.items);
18513 * Returns the first selected record.
18516 getSelected : function(){
18517 return this.selections.itemAt(0);
18522 * Clears all selections.
18524 clearSelections : function(fast){
18525 if(this.locked) return;
18527 var ds = this.grid.dataSource;
18528 var s = this.selections;
18529 s.each(function(r){
18530 this.deselectRow(ds.indexOfId(r.id));
18534 this.selections.clear();
18541 * Selects all rows.
18543 selectAll : function(){
18544 if(this.locked) return;
18545 this.selections.clear();
18546 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18547 this.selectRow(i, true);
18552 * Returns True if there is a selection.
18553 * @return {Boolean}
18555 hasSelection : function(){
18556 return this.selections.length > 0;
18560 * Returns True if the specified row is selected.
18561 * @param {Number/Record} record The record or index of the record to check
18562 * @return {Boolean}
18564 isSelected : function(index){
18565 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18566 return (r && this.selections.key(r.id) ? true : false);
18570 * Returns True if the specified record id is selected.
18571 * @param {String} id The id of record to check
18572 * @return {Boolean}
18574 isIdSelected : function(id){
18575 return (this.selections.key(id) ? true : false);
18579 handleMouseDown : function(e, t){
18580 var view = this.grid.getView(), rowIndex;
18581 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18584 if(e.shiftKey && this.last !== false){
18585 var last = this.last;
18586 this.selectRange(last, rowIndex, e.ctrlKey);
18587 this.last = last; // reset the last
18588 view.focusRow(rowIndex);
18590 var isSelected = this.isSelected(rowIndex);
18591 if(e.button !== 0 && isSelected){
18592 view.focusRow(rowIndex);
18593 }else if(e.ctrlKey && isSelected){
18594 this.deselectRow(rowIndex);
18595 }else if(!isSelected){
18596 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18597 view.focusRow(rowIndex);
18600 this.fireEvent("afterselectionchange", this);
18603 handleDragableRowClick : function(grid, rowIndex, e)
18605 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18606 this.selectRow(rowIndex, false);
18607 grid.view.focusRow(rowIndex);
18608 this.fireEvent("afterselectionchange", this);
18613 * Selects multiple rows.
18614 * @param {Array} rows Array of the indexes of the row to select
18615 * @param {Boolean} keepExisting (optional) True to keep existing selections
18617 selectRows : function(rows, keepExisting){
18619 this.clearSelections();
18621 for(var i = 0, len = rows.length; i < len; i++){
18622 this.selectRow(rows[i], true);
18627 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18628 * @param {Number} startRow The index of the first row in the range
18629 * @param {Number} endRow The index of the last row in the range
18630 * @param {Boolean} keepExisting (optional) True to retain existing selections
18632 selectRange : function(startRow, endRow, keepExisting){
18633 if(this.locked) return;
18635 this.clearSelections();
18637 if(startRow <= endRow){
18638 for(var i = startRow; i <= endRow; i++){
18639 this.selectRow(i, true);
18642 for(var i = startRow; i >= endRow; i--){
18643 this.selectRow(i, true);
18649 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18650 * @param {Number} startRow The index of the first row in the range
18651 * @param {Number} endRow The index of the last row in the range
18653 deselectRange : function(startRow, endRow, preventViewNotify){
18654 if(this.locked) return;
18655 for(var i = startRow; i <= endRow; i++){
18656 this.deselectRow(i, preventViewNotify);
18662 * @param {Number} row The index of the row to select
18663 * @param {Boolean} keepExisting (optional) True to keep existing selections
18665 selectRow : function(index, keepExisting, preventViewNotify){
18666 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18667 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18668 if(!keepExisting || this.singleSelect){
18669 this.clearSelections();
18671 var r = this.grid.dataSource.getAt(index);
18672 this.selections.add(r);
18673 this.last = this.lastActive = index;
18674 if(!preventViewNotify){
18675 this.grid.getView().onRowSelect(index);
18677 this.fireEvent("rowselect", this, index, r);
18678 this.fireEvent("selectionchange", this);
18684 * @param {Number} row The index of the row to deselect
18686 deselectRow : function(index, preventViewNotify){
18687 if(this.locked) return;
18688 if(this.last == index){
18691 if(this.lastActive == index){
18692 this.lastActive = false;
18694 var r = this.grid.dataSource.getAt(index);
18695 this.selections.remove(r);
18696 if(!preventViewNotify){
18697 this.grid.getView().onRowDeselect(index);
18699 this.fireEvent("rowdeselect", this, index);
18700 this.fireEvent("selectionchange", this);
18704 restoreLast : function(){
18706 this.last = this._last;
18711 acceptsNav : function(row, col, cm){
18712 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18716 onEditorKey : function(field, e){
18717 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18722 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18724 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18726 }else if(k == e.ENTER && !e.ctrlKey){
18730 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18732 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18734 }else if(k == e.ESC){
18738 g.startEditing(newCell[0], newCell[1]);
18743 * Ext JS Library 1.1.1
18744 * Copyright(c) 2006-2007, Ext JS, LLC.
18746 * Originally Released Under LGPL - original licence link has changed is not relivant.
18749 * <script type="text/javascript">
18753 * @class Roo.bootstrap.PagingToolbar
18755 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18757 * Create a new PagingToolbar
18758 * @param {Object} config The config object
18760 Roo.bootstrap.PagingToolbar = function(config)
18762 // old args format still supported... - xtype is prefered..
18763 // created from xtype...
18764 var ds = config.dataSource;
18765 this.toolbarItems = [];
18766 if (config.items) {
18767 this.toolbarItems = config.items;
18768 // config.items = [];
18771 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18778 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18782 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18784 * @cfg {Roo.data.Store} dataSource
18785 * The underlying data store providing the paged data
18788 * @cfg {String/HTMLElement/Element} container
18789 * container The id or element that will contain the toolbar
18792 * @cfg {Boolean} displayInfo
18793 * True to display the displayMsg (defaults to false)
18796 * @cfg {Number} pageSize
18797 * The number of records to display per page (defaults to 20)
18801 * @cfg {String} displayMsg
18802 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18804 displayMsg : 'Displaying {0} - {1} of {2}',
18806 * @cfg {String} emptyMsg
18807 * The message to display when no records are found (defaults to "No data to display")
18809 emptyMsg : 'No data to display',
18811 * Customizable piece of the default paging text (defaults to "Page")
18814 beforePageText : "Page",
18816 * Customizable piece of the default paging text (defaults to "of %0")
18819 afterPageText : "of {0}",
18821 * Customizable piece of the default paging text (defaults to "First Page")
18824 firstText : "First Page",
18826 * Customizable piece of the default paging text (defaults to "Previous Page")
18829 prevText : "Previous Page",
18831 * Customizable piece of the default paging text (defaults to "Next Page")
18834 nextText : "Next Page",
18836 * Customizable piece of the default paging text (defaults to "Last Page")
18839 lastText : "Last Page",
18841 * Customizable piece of the default paging text (defaults to "Refresh")
18844 refreshText : "Refresh",
18848 onRender : function(ct, position)
18850 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18851 this.navgroup.parentId = this.id;
18852 this.navgroup.onRender(this.el, null);
18853 // add the buttons to the navgroup
18855 if(this.displayInfo){
18856 Roo.log(this.el.select('ul.navbar-nav',true).first());
18857 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18858 this.displayEl = this.el.select('.x-paging-info', true).first();
18859 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18860 // this.displayEl = navel.el.select('span',true).first();
18866 Roo.each(_this.buttons, function(e){
18867 Roo.factory(e).onRender(_this.el, null);
18871 Roo.each(_this.toolbarItems, function(e) {
18872 _this.navgroup.addItem(e);
18875 this.first = this.navgroup.addItem({
18876 tooltip: this.firstText,
18878 icon : 'fa fa-backward',
18880 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18883 this.prev = this.navgroup.addItem({
18884 tooltip: this.prevText,
18886 icon : 'fa fa-step-backward',
18888 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18890 //this.addSeparator();
18893 var field = this.navgroup.addItem( {
18895 cls : 'x-paging-position',
18897 html : this.beforePageText +
18898 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18899 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18902 this.field = field.el.select('input', true).first();
18903 this.field.on("keydown", this.onPagingKeydown, this);
18904 this.field.on("focus", function(){this.dom.select();});
18907 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18908 //this.field.setHeight(18);
18909 //this.addSeparator();
18910 this.next = this.navgroup.addItem({
18911 tooltip: this.nextText,
18913 html : ' <i class="fa fa-step-forward">',
18915 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18917 this.last = this.navgroup.addItem({
18918 tooltip: this.lastText,
18919 icon : 'fa fa-forward',
18922 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18924 //this.addSeparator();
18925 this.loading = this.navgroup.addItem({
18926 tooltip: this.refreshText,
18927 icon: 'fa fa-refresh',
18929 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18935 updateInfo : function(){
18936 if(this.displayEl){
18937 var count = this.ds.getCount();
18938 var msg = count == 0 ?
18942 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18944 this.displayEl.update(msg);
18949 onLoad : function(ds, r, o){
18950 this.cursor = o.params ? o.params.start : 0;
18951 var d = this.getPageData(),
18955 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18956 this.field.dom.value = ap;
18957 this.first.setDisabled(ap == 1);
18958 this.prev.setDisabled(ap == 1);
18959 this.next.setDisabled(ap == ps);
18960 this.last.setDisabled(ap == ps);
18961 this.loading.enable();
18966 getPageData : function(){
18967 var total = this.ds.getTotalCount();
18970 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18971 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18976 onLoadError : function(){
18977 this.loading.enable();
18981 onPagingKeydown : function(e){
18982 var k = e.getKey();
18983 var d = this.getPageData();
18985 var v = this.field.dom.value, pageNum;
18986 if(!v || isNaN(pageNum = parseInt(v, 10))){
18987 this.field.dom.value = d.activePage;
18990 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18991 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18994 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))
18996 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18997 this.field.dom.value = pageNum;
18998 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19001 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19003 var v = this.field.dom.value, pageNum;
19004 var increment = (e.shiftKey) ? 10 : 1;
19005 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19007 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19008 this.field.dom.value = d.activePage;
19011 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19013 this.field.dom.value = parseInt(v, 10) + increment;
19014 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19015 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19022 beforeLoad : function(){
19024 this.loading.disable();
19029 onClick : function(which){
19036 ds.load({params:{start: 0, limit: this.pageSize}});
19039 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19042 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19045 var total = ds.getTotalCount();
19046 var extra = total % this.pageSize;
19047 var lastStart = extra ? (total - extra) : total-this.pageSize;
19048 ds.load({params:{start: lastStart, limit: this.pageSize}});
19051 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19057 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19058 * @param {Roo.data.Store} store The data store to unbind
19060 unbind : function(ds){
19061 ds.un("beforeload", this.beforeLoad, this);
19062 ds.un("load", this.onLoad, this);
19063 ds.un("loadexception", this.onLoadError, this);
19064 ds.un("remove", this.updateInfo, this);
19065 ds.un("add", this.updateInfo, this);
19066 this.ds = undefined;
19070 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19071 * @param {Roo.data.Store} store The data store to bind
19073 bind : function(ds){
19074 ds.on("beforeload", this.beforeLoad, this);
19075 ds.on("load", this.onLoad, this);
19076 ds.on("loadexception", this.onLoadError, this);
19077 ds.on("remove", this.updateInfo, this);
19078 ds.on("add", this.updateInfo, this);
19089 * @class Roo.bootstrap.MessageBar
19090 * @extends Roo.bootstrap.Component
19091 * Bootstrap MessageBar class
19092 * @cfg {String} html contents of the MessageBar
19093 * @cfg {String} weight (info | success | warning | danger) default info
19094 * @cfg {String} beforeClass insert the bar before the given class
19095 * @cfg {Boolean} closable (true | false) default false
19096 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19099 * Create a new Element
19100 * @param {Object} config The config object
19103 Roo.bootstrap.MessageBar = function(config){
19104 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19107 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19113 beforeClass: 'bootstrap-sticky-wrap',
19115 getAutoCreate : function(){
19119 cls: 'alert alert-dismissable alert-' + this.weight,
19124 html: this.html || ''
19130 cfg.cls += ' alert-messages-fixed';
19144 onRender : function(ct, position)
19146 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19149 var cfg = Roo.apply({}, this.getAutoCreate());
19153 cfg.cls += ' ' + this.cls;
19156 cfg.style = this.style;
19158 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19160 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19163 this.el.select('>button.close').on('click', this.hide, this);
19169 if (!this.rendered) {
19175 this.fireEvent('show', this);
19181 if (!this.rendered) {
19187 this.fireEvent('hide', this);
19190 update : function()
19192 // var e = this.el.dom.firstChild;
19194 // if(this.closable){
19195 // e = e.nextSibling;
19198 // e.data = this.html || '';
19200 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19216 * @class Roo.bootstrap.Graph
19217 * @extends Roo.bootstrap.Component
19218 * Bootstrap Graph class
19222 @cfg {String} graphtype bar | vbar | pie
19223 @cfg {number} g_x coodinator | centre x (pie)
19224 @cfg {number} g_y coodinator | centre y (pie)
19225 @cfg {number} g_r radius (pie)
19226 @cfg {number} g_height height of the chart (respected by all elements in the set)
19227 @cfg {number} g_width width of the chart (respected by all elements in the set)
19228 @cfg {Object} title The title of the chart
19231 -opts (object) options for the chart
19233 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19234 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19236 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.
19237 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19239 o stretch (boolean)
19241 -opts (object) options for the pie
19244 o startAngle (number)
19245 o endAngle (number)
19249 * Create a new Input
19250 * @param {Object} config The config object
19253 Roo.bootstrap.Graph = function(config){
19254 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19260 * The img click event for the img.
19261 * @param {Roo.EventObject} e
19267 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19278 //g_colors: this.colors,
19285 getAutoCreate : function(){
19296 onRender : function(ct,position){
19297 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19298 this.raphael = Raphael(this.el.dom);
19300 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19301 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19302 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19303 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19305 r.text(160, 10, "Single Series Chart").attr(txtattr);
19306 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19307 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19308 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19310 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19311 r.barchart(330, 10, 300, 220, data1);
19312 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19313 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19316 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19317 // r.barchart(30, 30, 560, 250, xdata, {
19318 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19319 // axis : "0 0 1 1",
19320 // axisxlabels : xdata
19321 // //yvalues : cols,
19324 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19326 // this.load(null,xdata,{
19327 // axis : "0 0 1 1",
19328 // axisxlabels : xdata
19333 load : function(graphtype,xdata,opts){
19334 this.raphael.clear();
19336 graphtype = this.graphtype;
19341 var r = this.raphael,
19342 fin = function () {
19343 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19345 fout = function () {
19346 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19348 pfin = function() {
19349 this.sector.stop();
19350 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19353 this.label[0].stop();
19354 this.label[0].attr({ r: 7.5 });
19355 this.label[1].attr({ "font-weight": 800 });
19358 pfout = function() {
19359 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19362 this.label[0].animate({ r: 5 }, 500, "bounce");
19363 this.label[1].attr({ "font-weight": 400 });
19369 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19372 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19375 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19376 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19378 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19385 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19390 setTitle: function(o)
19395 initEvents: function() {
19398 this.el.on('click', this.onClick, this);
19402 onClick : function(e)
19404 Roo.log('img onclick');
19405 this.fireEvent('click', this, e);
19417 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19420 * @class Roo.bootstrap.dash.NumberBox
19421 * @extends Roo.bootstrap.Component
19422 * Bootstrap NumberBox class
19423 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19424 * @cfg {String} headline Box headline
19425 * @cfg {String} content Box content
19426 * @cfg {String} icon Box icon
19427 * @cfg {String} footer Footer text
19428 * @cfg {String} fhref Footer href
19431 * Create a new NumberBox
19432 * @param {Object} config The config object
19436 Roo.bootstrap.dash.NumberBox = function(config){
19437 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19441 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19451 getAutoCreate : function(){
19455 cls : 'small-box bg-' + this.bgcolor,
19463 cls : 'roo-headline',
19464 html : this.headline
19468 cls : 'roo-content',
19469 html : this.content
19483 cls : 'ion ' + this.icon
19492 cls : 'small-box-footer',
19493 href : this.fhref || '#',
19497 cfg.cn.push(footer);
19504 onRender : function(ct,position){
19505 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19512 setHeadline: function (value)
19514 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19517 setFooter: function (value, href)
19519 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19522 this.el.select('a.small-box-footer',true).first().attr('href', href);
19527 setContent: function (value)
19529 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19532 initEvents: function()
19546 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19549 * @class Roo.bootstrap.dash.TabBox
19550 * @extends Roo.bootstrap.Component
19551 * Bootstrap TabBox class
19552 * @cfg {String} title Title of the TabBox
19553 * @cfg {String} icon Icon of the TabBox
19554 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19557 * Create a new TabBox
19558 * @param {Object} config The config object
19562 Roo.bootstrap.dash.TabBox = function(config){
19563 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19568 * When a pane is added
19569 * @param {Roo.bootstrap.dash.TabPane} pane
19576 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19582 getChildContainer : function()
19584 return this.el.select('.tab-content', true).first();
19587 getAutoCreate : function(){
19591 cls: 'pull-left header',
19599 cls: 'fa ' + this.icon
19606 cls: 'nav-tabs-custom',
19610 cls: 'nav nav-tabs pull-right',
19617 cls: 'tab-content no-padding',
19625 initEvents : function()
19627 //Roo.log('add add pane handler');
19628 this.on('addpane', this.onAddPane, this);
19631 * Updates the box title
19632 * @param {String} html to set the title to.
19634 setTitle : function(value)
19636 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19638 onAddPane : function(pane)
19640 //Roo.log('addpane');
19642 // tabs are rendere left to right..
19643 if(!this.showtabs){
19647 var ctr = this.el.select('.nav-tabs', true).first();
19650 var existing = ctr.select('.nav-tab',true);
19651 var qty = existing.getCount();;
19654 var tab = ctr.createChild({
19656 cls : 'nav-tab' + (qty ? '' : ' active'),
19664 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19667 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19669 pane.el.addClass('active');
19674 onTabClick : function(ev,un,ob,pane)
19676 //Roo.log('tab - prev default');
19677 ev.preventDefault();
19680 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19681 pane.tab.addClass('active');
19682 //Roo.log(pane.title);
19683 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19684 // technically we should have a deactivate event.. but maybe add later.
19685 // and it should not de-activate the selected tab...
19687 pane.el.addClass('active');
19688 pane.fireEvent('activate');
19703 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19705 * @class Roo.bootstrap.TabPane
19706 * @extends Roo.bootstrap.Component
19707 * Bootstrap TabPane class
19708 * @cfg {Boolean} active (false | true) Default false
19709 * @cfg {String} title title of panel
19713 * Create a new TabPane
19714 * @param {Object} config The config object
19717 Roo.bootstrap.dash.TabPane = function(config){
19718 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19722 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19727 // the tabBox that this is attached to.
19730 getAutoCreate : function()
19738 cfg.cls += ' active';
19743 initEvents : function()
19745 //Roo.log('trigger add pane handler');
19746 this.parent().fireEvent('addpane', this)
19750 * Updates the tab title
19751 * @param {String} html to set the title to.
19753 setTitle: function(str)
19759 this.tab.select('a'.true).first().dom.innerHTML = str;
19776 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19779 * @class Roo.bootstrap.menu.Menu
19780 * @extends Roo.bootstrap.Component
19781 * Bootstrap Menu class - container for Menu
19782 * @cfg {String} html Text of the menu
19783 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19784 * @cfg {String} icon Font awesome icon
19785 * @cfg {String} pos Menu align to (top | bottom) default bottom
19789 * Create a new Menu
19790 * @param {Object} config The config object
19794 Roo.bootstrap.menu.Menu = function(config){
19795 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19799 * @event beforeshow
19800 * Fires before this menu is displayed
19801 * @param {Roo.bootstrap.menu.Menu} this
19805 * @event beforehide
19806 * Fires before this menu is hidden
19807 * @param {Roo.bootstrap.menu.Menu} this
19812 * Fires after this menu is displayed
19813 * @param {Roo.bootstrap.menu.Menu} this
19818 * Fires after this menu is hidden
19819 * @param {Roo.bootstrap.menu.Menu} this
19824 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19825 * @param {Roo.bootstrap.menu.Menu} this
19826 * @param {Roo.EventObject} e
19833 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19837 weight : 'default',
19842 getChildContainer : function() {
19843 if(this.isSubMenu){
19847 return this.el.select('ul.dropdown-menu', true).first();
19850 getAutoCreate : function()
19855 cls : 'roo-menu-text',
19863 cls : 'fa ' + this.icon
19874 cls : 'dropdown-button btn btn-' + this.weight,
19879 cls : 'dropdown-toggle btn btn-' + this.weight,
19889 cls : 'dropdown-menu'
19895 if(this.pos == 'top'){
19896 cfg.cls += ' dropup';
19899 if(this.isSubMenu){
19902 cls : 'dropdown-menu'
19909 onRender : function(ct, position)
19911 this.isSubMenu = ct.hasClass('dropdown-submenu');
19913 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19916 initEvents : function()
19918 if(this.isSubMenu){
19922 this.hidden = true;
19924 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19925 this.triggerEl.on('click', this.onTriggerPress, this);
19927 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19928 this.buttonEl.on('click', this.onClick, this);
19934 if(this.isSubMenu){
19938 return this.el.select('ul.dropdown-menu', true).first();
19941 onClick : function(e)
19943 this.fireEvent("click", this, e);
19946 onTriggerPress : function(e)
19948 if (this.isVisible()) {
19955 isVisible : function(){
19956 return !this.hidden;
19961 this.fireEvent("beforeshow", this);
19963 this.hidden = false;
19964 this.el.addClass('open');
19966 Roo.get(document).on("mouseup", this.onMouseUp, this);
19968 this.fireEvent("show", this);
19975 this.fireEvent("beforehide", this);
19977 this.hidden = true;
19978 this.el.removeClass('open');
19980 Roo.get(document).un("mouseup", this.onMouseUp);
19982 this.fireEvent("hide", this);
19985 onMouseUp : function()
19999 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20002 * @class Roo.bootstrap.menu.Item
20003 * @extends Roo.bootstrap.Component
20004 * Bootstrap MenuItem class
20005 * @cfg {Boolean} submenu (true | false) default false
20006 * @cfg {String} html text of the item
20007 * @cfg {String} href the link
20008 * @cfg {Boolean} disable (true | false) default false
20009 * @cfg {Boolean} preventDefault (true | false) default true
20010 * @cfg {String} icon Font awesome icon
20011 * @cfg {String} pos Submenu align to (left | right) default right
20015 * Create a new Item
20016 * @param {Object} config The config object
20020 Roo.bootstrap.menu.Item = function(config){
20021 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20025 * Fires when the mouse is hovering over this menu
20026 * @param {Roo.bootstrap.menu.Item} this
20027 * @param {Roo.EventObject} e
20032 * Fires when the mouse exits this menu
20033 * @param {Roo.bootstrap.menu.Item} this
20034 * @param {Roo.EventObject} e
20040 * The raw click event for the entire grid.
20041 * @param {Roo.EventObject} e
20047 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20052 preventDefault: true,
20057 getAutoCreate : function()
20062 cls : 'roo-menu-item-text',
20070 cls : 'fa ' + this.icon
20079 href : this.href || '#',
20086 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20090 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20092 if(this.pos == 'left'){
20093 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20100 initEvents : function()
20102 this.el.on('mouseover', this.onMouseOver, this);
20103 this.el.on('mouseout', this.onMouseOut, this);
20105 this.el.select('a', true).first().on('click', this.onClick, this);
20109 onClick : function(e)
20111 if(this.preventDefault){
20112 e.preventDefault();
20115 this.fireEvent("click", this, e);
20118 onMouseOver : function(e)
20120 if(this.submenu && this.pos == 'left'){
20121 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20124 this.fireEvent("mouseover", this, e);
20127 onMouseOut : function(e)
20129 this.fireEvent("mouseout", this, e);
20141 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20144 * @class Roo.bootstrap.menu.Separator
20145 * @extends Roo.bootstrap.Component
20146 * Bootstrap Separator class
20149 * Create a new Separator
20150 * @param {Object} config The config object
20154 Roo.bootstrap.menu.Separator = function(config){
20155 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20158 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20160 getAutoCreate : function(){