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) {
3562 Roo.log("fire event clicked");
3563 if(this.fireEvent('click', this, e) === false){
3567 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3568 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3569 this.parent().setActiveItem(this);
3574 isActive: function () {
3577 setActive : function(state, fire, is_was_active)
3579 if (this.active && !state & this.navId) {
3580 this.was_active = true;
3581 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3583 nv.clearWasActive(this);
3587 this.active = state;
3590 this.el.removeClass('active');
3591 } else if (!this.el.hasClass('active')) {
3592 this.el.addClass('active');
3595 this.fireEvent('changed', this, state);
3598 // show a panel if it's registered and related..
3600 if (!this.navId || !this.tabId || !state || is_was_active) {
3604 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3608 var pan = tg.getPanelByName(this.tabId);
3612 // if we can not flip to new panel - go back to old nav highlight..
3613 if (false == tg.showPanel(pan)) {
3614 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3616 var onav = nv.getWasActive();
3618 onav.setActive(true, false, true);
3627 // this should not be here...
3628 setDisabled : function(state)
3630 this.disabled = state;
3632 this.el.removeClass('disabled');
3633 } else if (!this.el.hasClass('disabled')) {
3634 this.el.addClass('disabled');
3647 * <span> icon </span>
3648 * <span> text </span>
3649 * <span>badge </span>
3653 * @class Roo.bootstrap.NavSidebarItem
3654 * @extends Roo.bootstrap.NavItem
3655 * Bootstrap Navbar.NavSidebarItem class
3657 * Create a new Navbar Button
3658 * @param {Object} config The config object
3660 Roo.bootstrap.NavSidebarItem = function(config){
3661 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3666 * The raw click event for the entire grid.
3667 * @param {Roo.EventObject} e
3672 * Fires when the active item active state changes
3673 * @param {Roo.bootstrap.NavSidebarItem} this
3674 * @param {boolean} state the new state
3682 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3685 getAutoCreate : function(){
3690 href : this.href || '#',
3702 html : this.html || ''
3707 cfg.cls += ' active';
3711 if (this.glyphicon || this.icon) {
3712 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3713 a.cn.push({ tag : 'i', cls : c }) ;
3718 if (this.badge !== '') {
3719 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3723 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3724 a.cls += 'dropdown-toggle treeview' ;
3748 * @class Roo.bootstrap.Row
3749 * @extends Roo.bootstrap.Component
3750 * Bootstrap Row class (contains columns...)
3754 * @param {Object} config The config object
3757 Roo.bootstrap.Row = function(config){
3758 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3761 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3763 getAutoCreate : function(){
3782 * @class Roo.bootstrap.Element
3783 * @extends Roo.bootstrap.Component
3784 * Bootstrap Element class
3785 * @cfg {String} html contents of the element
3786 * @cfg {String} tag tag of the element
3787 * @cfg {String} cls class of the element
3790 * Create a new Element
3791 * @param {Object} config The config object
3794 Roo.bootstrap.Element = function(config){
3795 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3798 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3805 getAutoCreate : function(){
3830 * @class Roo.bootstrap.Pagination
3831 * @extends Roo.bootstrap.Component
3832 * Bootstrap Pagination class
3833 * @cfg {String} size xs | sm | md | lg
3834 * @cfg {Boolean} inverse false | true
3837 * Create a new Pagination
3838 * @param {Object} config The config object
3841 Roo.bootstrap.Pagination = function(config){
3842 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3845 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3851 getAutoCreate : function(){
3857 cfg.cls += ' inverse';
3863 cfg.cls += " " + this.cls;
3881 * @class Roo.bootstrap.PaginationItem
3882 * @extends Roo.bootstrap.Component
3883 * Bootstrap PaginationItem class
3884 * @cfg {String} html text
3885 * @cfg {String} href the link
3886 * @cfg {Boolean} preventDefault (true | false) default true
3887 * @cfg {Boolean} active (true | false) default false
3891 * Create a new PaginationItem
3892 * @param {Object} config The config object
3896 Roo.bootstrap.PaginationItem = function(config){
3897 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3902 * The raw click event for the entire grid.
3903 * @param {Roo.EventObject} e
3909 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3913 preventDefault: true,
3917 getAutoCreate : function(){
3923 href : this.href ? this.href : '#',
3924 html : this.html ? this.html : ''
3934 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3940 initEvents: function() {
3942 this.el.on('click', this.onClick, this);
3945 onClick : function(e)
3947 Roo.log('PaginationItem on click ');
3948 if(this.preventDefault){
3952 this.fireEvent('click', this, e);
3968 * @class Roo.bootstrap.Slider
3969 * @extends Roo.bootstrap.Component
3970 * Bootstrap Slider class
3973 * Create a new Slider
3974 * @param {Object} config The config object
3977 Roo.bootstrap.Slider = function(config){
3978 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3981 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3983 getAutoCreate : function(){
3987 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3991 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4003 * Ext JS Library 1.1.1
4004 * Copyright(c) 2006-2007, Ext JS, LLC.
4006 * Originally Released Under LGPL - original licence link has changed is not relivant.
4009 * <script type="text/javascript">
4014 * @class Roo.grid.ColumnModel
4015 * @extends Roo.util.Observable
4016 * This is the default implementation of a ColumnModel used by the Grid. It defines
4017 * the columns in the grid.
4020 var colModel = new Roo.grid.ColumnModel([
4021 {header: "Ticker", width: 60, sortable: true, locked: true},
4022 {header: "Company Name", width: 150, sortable: true},
4023 {header: "Market Cap.", width: 100, sortable: true},
4024 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4025 {header: "Employees", width: 100, sortable: true, resizable: false}
4030 * The config options listed for this class are options which may appear in each
4031 * individual column definition.
4032 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4034 * @param {Object} config An Array of column config objects. See this class's
4035 * config objects for details.
4037 Roo.grid.ColumnModel = function(config){
4039 * The config passed into the constructor
4041 this.config = config;
4044 // if no id, create one
4045 // if the column does not have a dataIndex mapping,
4046 // map it to the order it is in the config
4047 for(var i = 0, len = config.length; i < len; i++){
4049 if(typeof c.dataIndex == "undefined"){
4052 if(typeof c.renderer == "string"){
4053 c.renderer = Roo.util.Format[c.renderer];
4055 if(typeof c.id == "undefined"){
4058 if(c.editor && c.editor.xtype){
4059 c.editor = Roo.factory(c.editor, Roo.grid);
4061 if(c.editor && c.editor.isFormField){
4062 c.editor = new Roo.grid.GridEditor(c.editor);
4064 this.lookup[c.id] = c;
4068 * The width of columns which have no width specified (defaults to 100)
4071 this.defaultWidth = 100;
4074 * Default sortable of columns which have no sortable specified (defaults to false)
4077 this.defaultSortable = false;
4081 * @event widthchange
4082 * Fires when the width of a column changes.
4083 * @param {ColumnModel} this
4084 * @param {Number} columnIndex The column index
4085 * @param {Number} newWidth The new width
4087 "widthchange": true,
4089 * @event headerchange
4090 * Fires when the text of a header changes.
4091 * @param {ColumnModel} this
4092 * @param {Number} columnIndex The column index
4093 * @param {Number} newText The new header text
4095 "headerchange": true,
4097 * @event hiddenchange
4098 * Fires when a column is hidden or "unhidden".
4099 * @param {ColumnModel} this
4100 * @param {Number} columnIndex The column index
4101 * @param {Boolean} hidden true if hidden, false otherwise
4103 "hiddenchange": true,
4105 * @event columnmoved
4106 * Fires when a column is moved.
4107 * @param {ColumnModel} this
4108 * @param {Number} oldIndex
4109 * @param {Number} newIndex
4111 "columnmoved" : true,
4113 * @event columlockchange
4114 * Fires when a column's locked state is changed
4115 * @param {ColumnModel} this
4116 * @param {Number} colIndex
4117 * @param {Boolean} locked true if locked
4119 "columnlockchange" : true
4121 Roo.grid.ColumnModel.superclass.constructor.call(this);
4123 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4125 * @cfg {String} header The header text to display in the Grid view.
4128 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4129 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4130 * specified, the column's index is used as an index into the Record's data Array.
4133 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4134 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4137 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4138 * Defaults to the value of the {@link #defaultSortable} property.
4139 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4142 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4145 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4148 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4151 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4154 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4155 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4156 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4157 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4160 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4163 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4167 * Returns the id of the column at the specified index.
4168 * @param {Number} index The column index
4169 * @return {String} the id
4171 getColumnId : function(index){
4172 return this.config[index].id;
4176 * Returns the column for a specified id.
4177 * @param {String} id The column id
4178 * @return {Object} the column
4180 getColumnById : function(id){
4181 return this.lookup[id];
4186 * Returns the column for a specified dataIndex.
4187 * @param {String} dataIndex The column dataIndex
4188 * @return {Object|Boolean} the column or false if not found
4190 getColumnByDataIndex: function(dataIndex){
4191 var index = this.findColumnIndex(dataIndex);
4192 return index > -1 ? this.config[index] : false;
4196 * Returns the index for a specified column id.
4197 * @param {String} id The column id
4198 * @return {Number} the index, or -1 if not found
4200 getIndexById : function(id){
4201 for(var i = 0, len = this.config.length; i < len; i++){
4202 if(this.config[i].id == id){
4210 * Returns the index for a specified column dataIndex.
4211 * @param {String} dataIndex The column dataIndex
4212 * @return {Number} the index, or -1 if not found
4215 findColumnIndex : function(dataIndex){
4216 for(var i = 0, len = this.config.length; i < len; i++){
4217 if(this.config[i].dataIndex == dataIndex){
4225 moveColumn : function(oldIndex, newIndex){
4226 var c = this.config[oldIndex];
4227 this.config.splice(oldIndex, 1);
4228 this.config.splice(newIndex, 0, c);
4229 this.dataMap = null;
4230 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4233 isLocked : function(colIndex){
4234 return this.config[colIndex].locked === true;
4237 setLocked : function(colIndex, value, suppressEvent){
4238 if(this.isLocked(colIndex) == value){
4241 this.config[colIndex].locked = value;
4243 this.fireEvent("columnlockchange", this, colIndex, value);
4247 getTotalLockedWidth : function(){
4249 for(var i = 0; i < this.config.length; i++){
4250 if(this.isLocked(i) && !this.isHidden(i)){
4251 this.totalWidth += this.getColumnWidth(i);
4257 getLockedCount : function(){
4258 for(var i = 0, len = this.config.length; i < len; i++){
4259 if(!this.isLocked(i)){
4266 * Returns the number of columns.
4269 getColumnCount : function(visibleOnly){
4270 if(visibleOnly === true){
4272 for(var i = 0, len = this.config.length; i < len; i++){
4273 if(!this.isHidden(i)){
4279 return this.config.length;
4283 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4284 * @param {Function} fn
4285 * @param {Object} scope (optional)
4286 * @return {Array} result
4288 getColumnsBy : function(fn, scope){
4290 for(var i = 0, len = this.config.length; i < len; i++){
4291 var c = this.config[i];
4292 if(fn.call(scope||this, c, i) === true){
4300 * Returns true if the specified column is sortable.
4301 * @param {Number} col The column index
4304 isSortable : function(col){
4305 if(typeof this.config[col].sortable == "undefined"){
4306 return this.defaultSortable;
4308 return this.config[col].sortable;
4312 * Returns the rendering (formatting) function defined for the column.
4313 * @param {Number} col The column index.
4314 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4316 getRenderer : function(col){
4317 if(!this.config[col].renderer){
4318 return Roo.grid.ColumnModel.defaultRenderer;
4320 return this.config[col].renderer;
4324 * Sets the rendering (formatting) function for a column.
4325 * @param {Number} col The column index
4326 * @param {Function} fn The function to use to process the cell's raw data
4327 * to return HTML markup for the grid view. The render function is called with
4328 * the following parameters:<ul>
4329 * <li>Data value.</li>
4330 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4331 * <li>css A CSS style string to apply to the table cell.</li>
4332 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4333 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4334 * <li>Row index</li>
4335 * <li>Column index</li>
4336 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4338 setRenderer : function(col, fn){
4339 this.config[col].renderer = fn;
4343 * Returns the width for the specified column.
4344 * @param {Number} col The column index
4347 getColumnWidth : function(col){
4348 return this.config[col].width * 1 || this.defaultWidth;
4352 * Sets the width for a column.
4353 * @param {Number} col The column index
4354 * @param {Number} width The new width
4356 setColumnWidth : function(col, width, suppressEvent){
4357 this.config[col].width = width;
4358 this.totalWidth = null;
4360 this.fireEvent("widthchange", this, col, width);
4365 * Returns the total width of all columns.
4366 * @param {Boolean} includeHidden True to include hidden column widths
4369 getTotalWidth : function(includeHidden){
4370 if(!this.totalWidth){
4371 this.totalWidth = 0;
4372 for(var i = 0, len = this.config.length; i < len; i++){
4373 if(includeHidden || !this.isHidden(i)){
4374 this.totalWidth += this.getColumnWidth(i);
4378 return this.totalWidth;
4382 * Returns the header for the specified column.
4383 * @param {Number} col The column index
4386 getColumnHeader : function(col){
4387 return this.config[col].header;
4391 * Sets the header for a column.
4392 * @param {Number} col The column index
4393 * @param {String} header The new header
4395 setColumnHeader : function(col, header){
4396 this.config[col].header = header;
4397 this.fireEvent("headerchange", this, col, header);
4401 * Returns the tooltip for the specified column.
4402 * @param {Number} col The column index
4405 getColumnTooltip : function(col){
4406 return this.config[col].tooltip;
4409 * Sets the tooltip for a column.
4410 * @param {Number} col The column index
4411 * @param {String} tooltip The new tooltip
4413 setColumnTooltip : function(col, tooltip){
4414 this.config[col].tooltip = tooltip;
4418 * Returns the dataIndex for the specified column.
4419 * @param {Number} col The column index
4422 getDataIndex : function(col){
4423 return this.config[col].dataIndex;
4427 * Sets the dataIndex for a column.
4428 * @param {Number} col The column index
4429 * @param {Number} dataIndex The new dataIndex
4431 setDataIndex : function(col, dataIndex){
4432 this.config[col].dataIndex = dataIndex;
4438 * Returns true if the cell is editable.
4439 * @param {Number} colIndex The column index
4440 * @param {Number} rowIndex The row index
4443 isCellEditable : function(colIndex, rowIndex){
4444 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4448 * Returns the editor defined for the cell/column.
4449 * return false or null to disable editing.
4450 * @param {Number} colIndex The column index
4451 * @param {Number} rowIndex The row index
4454 getCellEditor : function(colIndex, rowIndex){
4455 return this.config[colIndex].editor;
4459 * Sets if a column is editable.
4460 * @param {Number} col The column index
4461 * @param {Boolean} editable True if the column is editable
4463 setEditable : function(col, editable){
4464 this.config[col].editable = editable;
4469 * Returns true if the column is hidden.
4470 * @param {Number} colIndex The column index
4473 isHidden : function(colIndex){
4474 return this.config[colIndex].hidden;
4479 * Returns true if the column width cannot be changed
4481 isFixed : function(colIndex){
4482 return this.config[colIndex].fixed;
4486 * Returns true if the column can be resized
4489 isResizable : function(colIndex){
4490 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4493 * Sets if a column is hidden.
4494 * @param {Number} colIndex The column index
4495 * @param {Boolean} hidden True if the column is hidden
4497 setHidden : function(colIndex, hidden){
4498 this.config[colIndex].hidden = hidden;
4499 this.totalWidth = null;
4500 this.fireEvent("hiddenchange", this, colIndex, hidden);
4504 * Sets the editor for a column.
4505 * @param {Number} col The column index
4506 * @param {Object} editor The editor object
4508 setEditor : function(col, editor){
4509 this.config[col].editor = editor;
4513 Roo.grid.ColumnModel.defaultRenderer = function(value){
4514 if(typeof value == "string" && value.length < 1){
4520 // Alias for backwards compatibility
4521 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4524 * Ext JS Library 1.1.1
4525 * Copyright(c) 2006-2007, Ext JS, LLC.
4527 * Originally Released Under LGPL - original licence link has changed is not relivant.
4530 * <script type="text/javascript">
4534 * @class Roo.LoadMask
4535 * A simple utility class for generically masking elements while loading data. If the element being masked has
4536 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4537 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4538 * element's UpdateManager load indicator and will be destroyed after the initial load.
4540 * Create a new LoadMask
4541 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4542 * @param {Object} config The config object
4544 Roo.LoadMask = function(el, config){
4545 this.el = Roo.get(el);
4546 Roo.apply(this, config);
4548 this.store.on('beforeload', this.onBeforeLoad, this);
4549 this.store.on('load', this.onLoad, this);
4550 this.store.on('loadexception', this.onLoadException, this);
4551 this.removeMask = false;
4553 var um = this.el.getUpdateManager();
4554 um.showLoadIndicator = false; // disable the default indicator
4555 um.on('beforeupdate', this.onBeforeLoad, this);
4556 um.on('update', this.onLoad, this);
4557 um.on('failure', this.onLoad, this);
4558 this.removeMask = true;
4562 Roo.LoadMask.prototype = {
4564 * @cfg {Boolean} removeMask
4565 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4566 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4570 * The text to display in a centered loading message box (defaults to 'Loading...')
4574 * @cfg {String} msgCls
4575 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4577 msgCls : 'x-mask-loading',
4580 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4586 * Disables the mask to prevent it from being displayed
4588 disable : function(){
4589 this.disabled = true;
4593 * Enables the mask so that it can be displayed
4595 enable : function(){
4596 this.disabled = false;
4599 onLoadException : function()
4603 if (typeof(arguments[3]) != 'undefined') {
4604 Roo.MessageBox.alert("Error loading",arguments[3]);
4608 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4609 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4618 this.el.unmask(this.removeMask);
4623 this.el.unmask(this.removeMask);
4627 onBeforeLoad : function(){
4629 this.el.mask(this.msg, this.msgCls);
4634 destroy : function(){
4636 this.store.un('beforeload', this.onBeforeLoad, this);
4637 this.store.un('load', this.onLoad, this);
4638 this.store.un('loadexception', this.onLoadException, this);
4640 var um = this.el.getUpdateManager();
4641 um.un('beforeupdate', this.onBeforeLoad, this);
4642 um.un('update', this.onLoad, this);
4643 um.un('failure', this.onLoad, this);
4654 * @class Roo.bootstrap.Table
4655 * @extends Roo.bootstrap.Component
4656 * Bootstrap Table class
4657 * @cfg {String} cls table class
4658 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4659 * @cfg {String} bgcolor Specifies the background color for a table
4660 * @cfg {Number} border Specifies whether the table cells should have borders or not
4661 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4662 * @cfg {Number} cellspacing Specifies the space between cells
4663 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4664 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4665 * @cfg {String} sortable Specifies that the table should be sortable
4666 * @cfg {String} summary Specifies a summary of the content of a table
4667 * @cfg {Number} width Specifies the width of a table
4668 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4670 * @cfg {boolean} striped Should the rows be alternative striped
4671 * @cfg {boolean} bordered Add borders to the table
4672 * @cfg {boolean} hover Add hover highlighting
4673 * @cfg {boolean} condensed Format condensed
4674 * @cfg {boolean} responsive Format condensed
4675 * @cfg {Boolean} loadMask (true|false) default false
4676 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4677 * @cfg {Boolean} thead (true|false) generate thead, default true
4678 * @cfg {Boolean} RowSelection (true|false) default false
4679 * @cfg {Boolean} CellSelection (true|false) default false
4681 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4685 * Create a new Table
4686 * @param {Object} config The config object
4689 Roo.bootstrap.Table = function(config){
4690 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4693 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4694 this.sm = this.selModel;
4695 this.sm.xmodule = this.xmodule || false;
4697 if (this.cm && typeof(this.cm.config) == 'undefined') {
4698 this.colModel = new Roo.grid.ColumnModel(this.cm);
4699 this.cm = this.colModel;
4700 this.cm.xmodule = this.xmodule || false;
4703 this.store= Roo.factory(this.store, Roo.data);
4704 this.ds = this.store;
4705 this.ds.xmodule = this.xmodule || false;
4708 if (this.footer && this.store) {
4709 this.footer.dataSource = this.ds;
4710 this.footer = Roo.factory(this.footer);
4717 * Fires when a cell is clicked
4718 * @param {Roo.bootstrap.Table} this
4719 * @param {Roo.Element} el
4720 * @param {Number} rowIndex
4721 * @param {Number} columnIndex
4722 * @param {Roo.EventObject} e
4726 * @event celldblclick
4727 * Fires when a cell is double clicked
4728 * @param {Roo.bootstrap.Table} this
4729 * @param {Roo.Element} el
4730 * @param {Number} rowIndex
4731 * @param {Number} columnIndex
4732 * @param {Roo.EventObject} e
4734 "celldblclick" : true,
4737 * Fires when a row is clicked
4738 * @param {Roo.bootstrap.Table} this
4739 * @param {Roo.Element} el
4740 * @param {Number} rowIndex
4741 * @param {Roo.EventObject} e
4745 * @event rowdblclick
4746 * Fires when a row is double clicked
4747 * @param {Roo.bootstrap.Table} this
4748 * @param {Roo.Element} el
4749 * @param {Number} rowIndex
4750 * @param {Roo.EventObject} e
4752 "rowdblclick" : true,
4755 * Fires when a mouseover occur
4756 * @param {Roo.bootstrap.Table} this
4757 * @param {Roo.Element} el
4758 * @param {Number} rowIndex
4759 * @param {Number} columnIndex
4760 * @param {Roo.EventObject} e
4765 * Fires when a mouseout occur
4766 * @param {Roo.bootstrap.Table} this
4767 * @param {Roo.Element} el
4768 * @param {Number} rowIndex
4769 * @param {Number} columnIndex
4770 * @param {Roo.EventObject} e
4775 * Fires when a row is rendered, so you can change add a style to it.
4776 * @param {Roo.bootstrap.Table} this
4777 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4784 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4808 RowSelection : false,
4809 CellSelection : false,
4812 // Roo.Element - the tbody
4815 getAutoCreate : function(){
4816 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4825 cfg.cls += ' table-striped';
4829 cfg.cls += ' table-hover';
4831 if (this.bordered) {
4832 cfg.cls += ' table-bordered';
4834 if (this.condensed) {
4835 cfg.cls += ' table-condensed';
4837 if (this.responsive) {
4838 cfg.cls += ' table-responsive';
4842 cfg.cls+= ' ' +this.cls;
4845 // this lot should be simplifed...
4848 cfg.align=this.align;
4851 cfg.bgcolor=this.bgcolor;
4854 cfg.border=this.border;
4856 if (this.cellpadding) {
4857 cfg.cellpadding=this.cellpadding;
4859 if (this.cellspacing) {
4860 cfg.cellspacing=this.cellspacing;
4863 cfg.frame=this.frame;
4866 cfg.rules=this.rules;
4868 if (this.sortable) {
4869 cfg.sortable=this.sortable;
4872 cfg.summary=this.summary;
4875 cfg.width=this.width;
4878 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4881 if(this.store || this.cm){
4883 cfg.cn.push(this.renderHeader());
4886 cfg.cn.push(this.renderBody());
4889 cfg.cn.push(this.renderFooter());
4892 cfg.cls+= ' TableGrid';
4895 return { cn : [ cfg ] };
4898 initEvents : function()
4900 if(!this.store || !this.cm){
4904 //Roo.log('initEvents with ds!!!!');
4906 this.mainBody = this.el.select('tbody', true).first();
4911 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4912 e.on('click', _this.sort, _this);
4915 this.el.on("click", this.onClick, this);
4916 this.el.on("dblclick", this.onDblClick, this);
4918 this.parent().el.setStyle('position', 'relative');
4920 this.footer.parentId = this.id;
4921 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4924 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4926 this.store.on('load', this.onLoad, this);
4927 this.store.on('beforeload', this.onBeforeLoad, this);
4928 this.store.on('update', this.onUpdate, this);
4932 onMouseover : function(e, el)
4934 var cell = Roo.get(el);
4940 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4941 cell = cell.findParent('td', false, true);
4944 var row = cell.findParent('tr', false, true);
4945 var cellIndex = cell.dom.cellIndex;
4946 var rowIndex = row.dom.rowIndex - 1; // start from 0
4948 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4952 onMouseout : function(e, el)
4954 var cell = Roo.get(el);
4960 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4961 cell = cell.findParent('td', false, true);
4964 var row = cell.findParent('tr', false, true);
4965 var cellIndex = cell.dom.cellIndex;
4966 var rowIndex = row.dom.rowIndex - 1; // start from 0
4968 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4972 onClick : function(e, el)
4974 var cell = Roo.get(el);
4976 if(!cell || (!this.CellSelection && !this.RowSelection)){
4981 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4982 cell = cell.findParent('td', false, true);
4985 var row = cell.findParent('tr', false, true);
4986 var cellIndex = cell.dom.cellIndex;
4987 var rowIndex = row.dom.rowIndex - 1;
4989 if(this.CellSelection){
4990 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4993 if(this.RowSelection){
4994 this.fireEvent('rowclick', this, row, rowIndex, e);
5000 onDblClick : function(e,el)
5002 var cell = Roo.get(el);
5004 if(!cell || (!this.CellSelection && !this.RowSelection)){
5008 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5009 cell = cell.findParent('td', false, true);
5012 var row = cell.findParent('tr', false, true);
5013 var cellIndex = cell.dom.cellIndex;
5014 var rowIndex = row.dom.rowIndex - 1;
5016 if(this.CellSelection){
5017 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5020 if(this.RowSelection){
5021 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5025 sort : function(e,el)
5027 var col = Roo.get(el)
5029 if(!col.hasClass('sortable')){
5033 var sort = col.attr('sort');
5036 if(col.hasClass('glyphicon-arrow-up')){
5040 this.store.sortInfo = {field : sort, direction : dir};
5043 Roo.log("calling footer first");
5044 this.footer.onClick('first');
5047 this.store.load({ params : { start : 0 } });
5051 renderHeader : function()
5060 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5062 var config = cm.config[i];
5067 html: cm.getColumnHeader(i)
5070 if(typeof(config.hidden) != 'undefined' && config.hidden){
5071 c.style += ' display:none;';
5074 if(typeof(config.dataIndex) != 'undefined'){
5075 c.sort = config.dataIndex;
5078 if(typeof(config.sortable) != 'undefined' && config.sortable){
5082 if(typeof(config.align) != 'undefined' && config.align.length){
5083 c.style += ' text-align:' + config.align + ';';
5086 if(typeof(config.width) != 'undefined'){
5087 c.style += ' width:' + config.width + 'px;';
5096 renderBody : function()
5106 colspan : this.cm.getColumnCount()
5116 renderFooter : function()
5126 colspan : this.cm.getColumnCount()
5140 Roo.log('ds onload');
5145 var ds = this.store;
5147 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5148 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5150 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5151 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5154 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5155 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5159 var tbody = this.mainBody;
5163 if(ds.getCount() > 0){
5164 ds.data.each(function(d,rowIndex){
5165 var row = this.renderRow(cm, ds, rowIndex);
5167 tbody.createChild(row);
5171 if(row.cellObjects.length){
5172 Roo.each(row.cellObjects, function(r){
5173 _this.renderCellObject(r);
5180 Roo.each(this.el.select('tbody td', true).elements, function(e){
5181 e.on('mouseover', _this.onMouseover, _this);
5184 Roo.each(this.el.select('tbody td', true).elements, function(e){
5185 e.on('mouseout', _this.onMouseout, _this);
5188 //if(this.loadMask){
5189 // this.maskEl.hide();
5194 onUpdate : function(ds,record)
5196 this.refreshRow(record);
5198 onRemove : function(ds, record, index, isUpdate){
5199 if(isUpdate !== true){
5200 this.fireEvent("beforerowremoved", this, index, record);
5202 var bt = this.mainBody.dom;
5204 bt.removeChild(bt.rows[index]);
5207 if(isUpdate !== true){
5208 //this.stripeRows(index);
5209 //this.syncRowHeights(index, index);
5211 this.fireEvent("rowremoved", this, index, record);
5216 refreshRow : function(record){
5217 var ds = this.store, index;
5218 if(typeof record == 'number'){
5220 record = ds.getAt(index);
5222 index = ds.indexOf(record);
5224 this.insertRow(ds, index, true);
5225 this.onRemove(ds, record, index+1, true);
5226 //this.syncRowHeights(index, index);
5228 this.fireEvent("rowupdated", this, index, record);
5231 insertRow : function(dm, rowIndex, isUpdate){
5234 this.fireEvent("beforerowsinserted", this, rowIndex);
5236 //var s = this.getScrollState();
5237 var row = this.renderRow(this.cm, this.store, rowIndex);
5238 // insert before rowIndex..
5239 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5244 if(row.cellObjects.length){
5245 Roo.each(row.cellObjects, function(r){
5246 _this.renderCellObject(r);
5251 this.fireEvent("rowsinserted", this, rowIndex);
5252 //this.syncRowHeights(firstRow, lastRow);
5253 //this.stripeRows(firstRow);
5260 getRowDom : function(rowIndex)
5262 // not sure if I need to check this.. but let's do it anyway..
5263 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5264 this.mainBody.dom.rows[rowIndex] : false
5266 // returns the object tree for a tr..
5269 renderRow : function(cm, ds, rowIndex) {
5271 var d = ds.getAt(rowIndex);
5278 var cellObjects = [];
5280 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5281 var config = cm.config[i];
5283 var renderer = cm.getRenderer(i);
5287 if(typeof(renderer) !== 'undefined'){
5288 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5290 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5291 // and are rendered into the cells after the row is rendered - using the id for the element.
5293 if(typeof(value) === 'object'){
5303 rowIndex : rowIndex,
5308 this.fireEvent('rowclass', this, rowcfg);
5312 cls : rowcfg.rowClass,
5314 html: (typeof(value) === 'object') ? '' : value
5321 if(typeof(config.hidden) != 'undefined' && config.hidden){
5322 td.style += ' display:none;';
5325 if(typeof(config.align) != 'undefined' && config.align.length){
5326 td.style += ' text-align:' + config.align + ';';
5329 if(typeof(config.width) != 'undefined'){
5330 td.style += ' width:' + config.width + 'px;';
5337 row.cellObjects = cellObjects;
5345 onBeforeLoad : function()
5347 //Roo.log('ds onBeforeLoad');
5351 //if(this.loadMask){
5352 // this.maskEl.show();
5358 this.el.select('tbody', true).first().dom.innerHTML = '';
5361 getSelectionModel : function(){
5363 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5365 return this.selModel;
5368 * Render the Roo.bootstrap object from renderder
5370 renderCellObject : function(r)
5374 var t = r.cfg.render(r.container);
5377 Roo.each(r.cfg.cn, function(c){
5379 container: t.getChildContainer(),
5382 _this.renderCellObject(child);
5399 * @class Roo.bootstrap.TableCell
5400 * @extends Roo.bootstrap.Component
5401 * Bootstrap TableCell class
5402 * @cfg {String} html cell contain text
5403 * @cfg {String} cls cell class
5404 * @cfg {String} tag cell tag (td|th) default td
5405 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5406 * @cfg {String} align Aligns the content in a cell
5407 * @cfg {String} axis Categorizes cells
5408 * @cfg {String} bgcolor Specifies the background color of a cell
5409 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5410 * @cfg {Number} colspan Specifies the number of columns a cell should span
5411 * @cfg {String} headers Specifies one or more header cells a cell is related to
5412 * @cfg {Number} height Sets the height of a cell
5413 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5414 * @cfg {Number} rowspan Sets the number of rows a cell should span
5415 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5416 * @cfg {String} valign Vertical aligns the content in a cell
5417 * @cfg {Number} width Specifies the width of a cell
5420 * Create a new TableCell
5421 * @param {Object} config The config object
5424 Roo.bootstrap.TableCell = function(config){
5425 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5428 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5448 getAutoCreate : function(){
5449 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5469 cfg.align=this.align
5475 cfg.bgcolor=this.bgcolor
5478 cfg.charoff=this.charoff
5481 cfg.colspan=this.colspan
5484 cfg.headers=this.headers
5487 cfg.height=this.height
5490 cfg.nowrap=this.nowrap
5493 cfg.rowspan=this.rowspan
5496 cfg.scope=this.scope
5499 cfg.valign=this.valign
5502 cfg.width=this.width
5521 * @class Roo.bootstrap.TableRow
5522 * @extends Roo.bootstrap.Component
5523 * Bootstrap TableRow class
5524 * @cfg {String} cls row class
5525 * @cfg {String} align Aligns the content in a table row
5526 * @cfg {String} bgcolor Specifies a background color for a table row
5527 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5528 * @cfg {String} valign Vertical aligns the content in a table row
5531 * Create a new TableRow
5532 * @param {Object} config The config object
5535 Roo.bootstrap.TableRow = function(config){
5536 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5539 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5547 getAutoCreate : function(){
5548 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5558 cfg.align = this.align;
5561 cfg.bgcolor = this.bgcolor;
5564 cfg.charoff = this.charoff;
5567 cfg.valign = this.valign;
5585 * @class Roo.bootstrap.TableBody
5586 * @extends Roo.bootstrap.Component
5587 * Bootstrap TableBody class
5588 * @cfg {String} cls element class
5589 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5590 * @cfg {String} align Aligns the content inside the element
5591 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5592 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5595 * Create a new TableBody
5596 * @param {Object} config The config object
5599 Roo.bootstrap.TableBody = function(config){
5600 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5603 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5611 getAutoCreate : function(){
5612 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5626 cfg.align = this.align;
5629 cfg.charoff = this.charoff;
5632 cfg.valign = this.valign;
5639 // initEvents : function()
5646 // this.store = Roo.factory(this.store, Roo.data);
5647 // this.store.on('load', this.onLoad, this);
5649 // this.store.load();
5653 // onLoad: function ()
5655 // this.fireEvent('load', this);
5665 * Ext JS Library 1.1.1
5666 * Copyright(c) 2006-2007, Ext JS, LLC.
5668 * Originally Released Under LGPL - original licence link has changed is not relivant.
5671 * <script type="text/javascript">
5674 // as we use this in bootstrap.
5675 Roo.namespace('Roo.form');
5677 * @class Roo.form.Action
5678 * Internal Class used to handle form actions
5680 * @param {Roo.form.BasicForm} el The form element or its id
5681 * @param {Object} config Configuration options
5686 // define the action interface
5687 Roo.form.Action = function(form, options){
5689 this.options = options || {};
5692 * Client Validation Failed
5695 Roo.form.Action.CLIENT_INVALID = 'client';
5697 * Server Validation Failed
5700 Roo.form.Action.SERVER_INVALID = 'server';
5702 * Connect to Server Failed
5705 Roo.form.Action.CONNECT_FAILURE = 'connect';
5707 * Reading Data from Server Failed
5710 Roo.form.Action.LOAD_FAILURE = 'load';
5712 Roo.form.Action.prototype = {
5714 failureType : undefined,
5715 response : undefined,
5719 run : function(options){
5724 success : function(response){
5729 handleResponse : function(response){
5733 // default connection failure
5734 failure : function(response){
5736 this.response = response;
5737 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5738 this.form.afterAction(this, false);
5741 processResponse : function(response){
5742 this.response = response;
5743 if(!response.responseText){
5746 this.result = this.handleResponse(response);
5750 // utility functions used internally
5751 getUrl : function(appendParams){
5752 var url = this.options.url || this.form.url || this.form.el.dom.action;
5754 var p = this.getParams();
5756 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5762 getMethod : function(){
5763 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5766 getParams : function(){
5767 var bp = this.form.baseParams;
5768 var p = this.options.params;
5770 if(typeof p == "object"){
5771 p = Roo.urlEncode(Roo.applyIf(p, bp));
5772 }else if(typeof p == 'string' && bp){
5773 p += '&' + Roo.urlEncode(bp);
5776 p = Roo.urlEncode(bp);
5781 createCallback : function(){
5783 success: this.success,
5784 failure: this.failure,
5786 timeout: (this.form.timeout*1000),
5787 upload: this.form.fileUpload ? this.success : undefined
5792 Roo.form.Action.Submit = function(form, options){
5793 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5796 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5799 haveProgress : false,
5800 uploadComplete : false,
5802 // uploadProgress indicator.
5803 uploadProgress : function()
5805 if (!this.form.progressUrl) {
5809 if (!this.haveProgress) {
5810 Roo.MessageBox.progress("Uploading", "Uploading");
5812 if (this.uploadComplete) {
5813 Roo.MessageBox.hide();
5817 this.haveProgress = true;
5819 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5821 var c = new Roo.data.Connection();
5823 url : this.form.progressUrl,
5828 success : function(req){
5829 //console.log(data);
5833 rdata = Roo.decode(req.responseText)
5835 Roo.log("Invalid data from server..");
5839 if (!rdata || !rdata.success) {
5841 Roo.MessageBox.alert(Roo.encode(rdata));
5844 var data = rdata.data;
5846 if (this.uploadComplete) {
5847 Roo.MessageBox.hide();
5852 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5853 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5856 this.uploadProgress.defer(2000,this);
5859 failure: function(data) {
5860 Roo.log('progress url failed ');
5871 // run get Values on the form, so it syncs any secondary forms.
5872 this.form.getValues();
5874 var o = this.options;
5875 var method = this.getMethod();
5876 var isPost = method == 'POST';
5877 if(o.clientValidation === false || this.form.isValid()){
5879 if (this.form.progressUrl) {
5880 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5881 (new Date() * 1) + '' + Math.random());
5886 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5887 form:this.form.el.dom,
5888 url:this.getUrl(!isPost),
5890 params:isPost ? this.getParams() : null,
5891 isUpload: this.form.fileUpload
5894 this.uploadProgress();
5896 }else if (o.clientValidation !== false){ // client validation failed
5897 this.failureType = Roo.form.Action.CLIENT_INVALID;
5898 this.form.afterAction(this, false);
5902 success : function(response)
5904 this.uploadComplete= true;
5905 if (this.haveProgress) {
5906 Roo.MessageBox.hide();
5910 var result = this.processResponse(response);
5911 if(result === true || result.success){
5912 this.form.afterAction(this, true);
5916 this.form.markInvalid(result.errors);
5917 this.failureType = Roo.form.Action.SERVER_INVALID;
5919 this.form.afterAction(this, false);
5921 failure : function(response)
5923 this.uploadComplete= true;
5924 if (this.haveProgress) {
5925 Roo.MessageBox.hide();
5928 this.response = response;
5929 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5930 this.form.afterAction(this, false);
5933 handleResponse : function(response){
5934 if(this.form.errorReader){
5935 var rs = this.form.errorReader.read(response);
5938 for(var i = 0, len = rs.records.length; i < len; i++) {
5939 var r = rs.records[i];
5943 if(errors.length < 1){
5947 success : rs.success,
5953 ret = Roo.decode(response.responseText);
5957 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5967 Roo.form.Action.Load = function(form, options){
5968 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5969 this.reader = this.form.reader;
5972 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5977 Roo.Ajax.request(Roo.apply(
5978 this.createCallback(), {
5979 method:this.getMethod(),
5980 url:this.getUrl(false),
5981 params:this.getParams()
5985 success : function(response){
5987 var result = this.processResponse(response);
5988 if(result === true || !result.success || !result.data){
5989 this.failureType = Roo.form.Action.LOAD_FAILURE;
5990 this.form.afterAction(this, false);
5993 this.form.clearInvalid();
5994 this.form.setValues(result.data);
5995 this.form.afterAction(this, true);
5998 handleResponse : function(response){
5999 if(this.form.reader){
6000 var rs = this.form.reader.read(response);
6001 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6003 success : rs.success,
6007 return Roo.decode(response.responseText);
6011 Roo.form.Action.ACTION_TYPES = {
6012 'load' : Roo.form.Action.Load,
6013 'submit' : Roo.form.Action.Submit
6022 * @class Roo.bootstrap.Form
6023 * @extends Roo.bootstrap.Component
6024 * Bootstrap Form class
6025 * @cfg {String} method GET | POST (default POST)
6026 * @cfg {String} labelAlign top | left (default top)
6027 * @cfg {String} align left | right - for navbars
6032 * @param {Object} config The config object
6036 Roo.bootstrap.Form = function(config){
6037 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6040 * @event clientvalidation
6041 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6042 * @param {Form} this
6043 * @param {Boolean} valid true if the form has passed client-side validation
6045 clientvalidation: true,
6047 * @event beforeaction
6048 * Fires before any action is performed. Return false to cancel the action.
6049 * @param {Form} this
6050 * @param {Action} action The action to be performed
6054 * @event actionfailed
6055 * Fires when an action fails.
6056 * @param {Form} this
6057 * @param {Action} action The action that failed
6059 actionfailed : true,
6061 * @event actioncomplete
6062 * Fires when an action is completed.
6063 * @param {Form} this
6064 * @param {Action} action The action that completed
6066 actioncomplete : true
6071 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6074 * @cfg {String} method
6075 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6080 * The URL to use for form actions if one isn't supplied in the action options.
6083 * @cfg {Boolean} fileUpload
6084 * Set to true if this form is a file upload.
6088 * @cfg {Object} baseParams
6089 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6093 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6097 * @cfg {Sting} align (left|right) for navbar forms
6102 activeAction : null,
6105 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6106 * element by passing it or its id or mask the form itself by passing in true.
6109 waitMsgTarget : false,
6114 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6115 * element by passing it or its id or mask the form itself by passing in true.
6119 getAutoCreate : function(){
6123 method : this.method || 'POST',
6124 id : this.id || Roo.id(),
6127 if (this.parent().xtype.match(/^Nav/)) {
6128 cfg.cls = 'navbar-form navbar-' + this.align;
6132 if (this.labelAlign == 'left' ) {
6133 cfg.cls += ' form-horizontal';
6139 initEvents : function()
6141 this.el.on('submit', this.onSubmit, this);
6142 // this was added as random key presses on the form where triggering form submit.
6143 this.el.on('keypress', function(e) {
6144 if (e.getCharCode() != 13) {
6147 // we might need to allow it for textareas.. and some other items.
6148 // check e.getTarget().
6150 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6154 Roo.log("keypress blocked");
6162 onSubmit : function(e){
6167 * Returns true if client-side validation on the form is successful.
6170 isValid : function(){
6171 var items = this.getItems();
6173 items.each(function(f){
6182 * Returns true if any fields in this form have changed since their original load.
6185 isDirty : function(){
6187 var items = this.getItems();
6188 items.each(function(f){
6198 * Performs a predefined action (submit or load) or custom actions you define on this form.
6199 * @param {String} actionName The name of the action type
6200 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6201 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6202 * accept other config options):
6204 Property Type Description
6205 ---------------- --------------- ----------------------------------------------------------------------------------
6206 url String The url for the action (defaults to the form's url)
6207 method String The form method to use (defaults to the form's method, or POST if not defined)
6208 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6209 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6210 validate the form on the client (defaults to false)
6212 * @return {BasicForm} this
6214 doAction : function(action, options){
6215 if(typeof action == 'string'){
6216 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6218 if(this.fireEvent('beforeaction', this, action) !== false){
6219 this.beforeAction(action);
6220 action.run.defer(100, action);
6226 beforeAction : function(action){
6227 var o = action.options;
6229 // not really supported yet.. ??
6231 //if(this.waitMsgTarget === true){
6232 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6233 //}else if(this.waitMsgTarget){
6234 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6235 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6237 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6243 afterAction : function(action, success){
6244 this.activeAction = null;
6245 var o = action.options;
6247 //if(this.waitMsgTarget === true){
6249 //}else if(this.waitMsgTarget){
6250 // this.waitMsgTarget.unmask();
6252 // Roo.MessageBox.updateProgress(1);
6253 // Roo.MessageBox.hide();
6260 Roo.callback(o.success, o.scope, [this, action]);
6261 this.fireEvent('actioncomplete', this, action);
6265 // failure condition..
6266 // we have a scenario where updates need confirming.
6267 // eg. if a locking scenario exists..
6268 // we look for { errors : { needs_confirm : true }} in the response.
6270 (typeof(action.result) != 'undefined') &&
6271 (typeof(action.result.errors) != 'undefined') &&
6272 (typeof(action.result.errors.needs_confirm) != 'undefined')
6275 Roo.log("not supported yet");
6278 Roo.MessageBox.confirm(
6279 "Change requires confirmation",
6280 action.result.errorMsg,
6285 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6295 Roo.callback(o.failure, o.scope, [this, action]);
6296 // show an error message if no failed handler is set..
6297 if (!this.hasListener('actionfailed')) {
6298 Roo.log("need to add dialog support");
6300 Roo.MessageBox.alert("Error",
6301 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6302 action.result.errorMsg :
6303 "Saving Failed, please check your entries or try again"
6308 this.fireEvent('actionfailed', this, action);
6313 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6314 * @param {String} id The value to search for
6317 findField : function(id){
6318 var items = this.getItems();
6319 var field = items.get(id);
6321 items.each(function(f){
6322 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6329 return field || null;
6332 * Mark fields in this form invalid in bulk.
6333 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6334 * @return {BasicForm} this
6336 markInvalid : function(errors){
6337 if(errors instanceof Array){
6338 for(var i = 0, len = errors.length; i < len; i++){
6339 var fieldError = errors[i];
6340 var f = this.findField(fieldError.id);
6342 f.markInvalid(fieldError.msg);
6348 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6349 field.markInvalid(errors[id]);
6353 //Roo.each(this.childForms || [], function (f) {
6354 // f.markInvalid(errors);
6361 * Set values for fields in this form in bulk.
6362 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6363 * @return {BasicForm} this
6365 setValues : function(values){
6366 if(values instanceof Array){ // array of objects
6367 for(var i = 0, len = values.length; i < len; i++){
6369 var f = this.findField(v.id);
6371 f.setValue(v.value);
6372 if(this.trackResetOnLoad){
6373 f.originalValue = f.getValue();
6377 }else{ // object hash
6380 if(typeof values[id] != 'function' && (field = this.findField(id))){
6382 if (field.setFromData &&
6384 field.displayField &&
6385 // combos' with local stores can
6386 // be queried via setValue()
6387 // to set their value..
6388 (field.store && !field.store.isLocal)
6392 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6393 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6394 field.setFromData(sd);
6397 field.setValue(values[id]);
6401 if(this.trackResetOnLoad){
6402 field.originalValue = field.getValue();
6408 //Roo.each(this.childForms || [], function (f) {
6409 // f.setValues(values);
6416 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6417 * they are returned as an array.
6418 * @param {Boolean} asString
6421 getValues : function(asString){
6422 //if (this.childForms) {
6423 // copy values from the child forms
6424 // Roo.each(this.childForms, function (f) {
6425 // this.setValues(f.getValues());
6431 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6432 if(asString === true){
6435 return Roo.urlDecode(fs);
6439 * Returns the fields in this form as an object with key/value pairs.
6440 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6443 getFieldValues : function(with_hidden)
6445 var items = this.getItems();
6447 items.each(function(f){
6451 var v = f.getValue();
6452 if (f.inputType =='radio') {
6453 if (typeof(ret[f.getName()]) == 'undefined') {
6454 ret[f.getName()] = ''; // empty..
6457 if (!f.el.dom.checked) {
6465 // not sure if this supported any more..
6466 if ((typeof(v) == 'object') && f.getRawValue) {
6467 v = f.getRawValue() ; // dates..
6469 // combo boxes where name != hiddenName...
6470 if (f.name != f.getName()) {
6471 ret[f.name] = f.getRawValue();
6473 ret[f.getName()] = v;
6480 * Clears all invalid messages in this form.
6481 * @return {BasicForm} this
6483 clearInvalid : function(){
6484 var items = this.getItems();
6486 items.each(function(f){
6497 * @return {BasicForm} this
6500 var items = this.getItems();
6501 items.each(function(f){
6505 Roo.each(this.childForms || [], function (f) {
6512 getItems : function()
6514 var r=new Roo.util.MixedCollection(false, function(o){
6515 return o.id || (o.id = Roo.id());
6517 var iter = function(el) {
6524 Roo.each(el.items,function(e) {
6543 * Ext JS Library 1.1.1
6544 * Copyright(c) 2006-2007, Ext JS, LLC.
6546 * Originally Released Under LGPL - original licence link has changed is not relivant.
6549 * <script type="text/javascript">
6552 * @class Roo.form.VTypes
6553 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6556 Roo.form.VTypes = function(){
6557 // closure these in so they are only created once.
6558 var alpha = /^[a-zA-Z_]+$/;
6559 var alphanum = /^[a-zA-Z0-9_]+$/;
6560 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6561 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6563 // All these messages and functions are configurable
6566 * The function used to validate email addresses
6567 * @param {String} value The email address
6569 'email' : function(v){
6570 return email.test(v);
6573 * The error text to display when the email validation function returns false
6576 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6578 * The keystroke filter mask to be applied on email input
6581 'emailMask' : /[a-z0-9_\.\-@]/i,
6584 * The function used to validate URLs
6585 * @param {String} value The URL
6587 'url' : function(v){
6591 * The error text to display when the url validation function returns false
6594 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6597 * The function used to validate alpha values
6598 * @param {String} value The value
6600 'alpha' : function(v){
6601 return alpha.test(v);
6604 * The error text to display when the alpha validation function returns false
6607 'alphaText' : 'This field should only contain letters and _',
6609 * The keystroke filter mask to be applied on alpha input
6612 'alphaMask' : /[a-z_]/i,
6615 * The function used to validate alphanumeric values
6616 * @param {String} value The value
6618 'alphanum' : function(v){
6619 return alphanum.test(v);
6622 * The error text to display when the alphanumeric validation function returns false
6625 'alphanumText' : 'This field should only contain letters, numbers and _',
6627 * The keystroke filter mask to be applied on alphanumeric input
6630 'alphanumMask' : /[a-z0-9_]/i
6640 * @class Roo.bootstrap.Input
6641 * @extends Roo.bootstrap.Component
6642 * Bootstrap Input class
6643 * @cfg {Boolean} disabled is it disabled
6644 * @cfg {String} fieldLabel - the label associated
6645 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6646 * @cfg {String} name name of the input
6647 * @cfg {string} fieldLabel - the label associated
6648 * @cfg {string} inputType - input / file submit ...
6649 * @cfg {string} placeholder - placeholder to put in text.
6650 * @cfg {string} before - input group add on before
6651 * @cfg {string} after - input group add on after
6652 * @cfg {string} size - (lg|sm) or leave empty..
6653 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6654 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6655 * @cfg {Number} md colspan out of 12 for computer-sized screens
6656 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6657 * @cfg {string} value default value of the input
6658 * @cfg {Number} labelWidth set the width of label (0-12)
6659 * @cfg {String} labelAlign (top|left)
6660 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6661 * @cfg {String} align (left|center|right) Default left
6665 * Create a new Input
6666 * @param {Object} config The config object
6669 Roo.bootstrap.Input = function(config){
6670 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6675 * Fires when this field receives input focus.
6676 * @param {Roo.form.Field} this
6681 * Fires when this field loses input focus.
6682 * @param {Roo.form.Field} this
6687 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6688 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6689 * @param {Roo.form.Field} this
6690 * @param {Roo.EventObject} e The event object
6695 * Fires just before the field blurs if the field value has changed.
6696 * @param {Roo.form.Field} this
6697 * @param {Mixed} newValue The new value
6698 * @param {Mixed} oldValue The original value
6703 * Fires after the field has been marked as invalid.
6704 * @param {Roo.form.Field} this
6705 * @param {String} msg The validation message
6710 * Fires after the field has been validated with no errors.
6711 * @param {Roo.form.Field} this
6716 * Fires after the key up
6717 * @param {Roo.form.Field} this
6718 * @param {Roo.EventObject} e The event Object
6724 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6726 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6727 automatic validation (defaults to "keyup").
6729 validationEvent : "keyup",
6731 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6733 validateOnBlur : true,
6735 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6737 validationDelay : 250,
6739 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6741 focusClass : "x-form-focus", // not needed???
6745 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6747 invalidClass : "has-error",
6750 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6752 selectOnFocus : false,
6755 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6759 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6764 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6766 disableKeyFilter : false,
6769 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6773 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6777 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6779 blankText : "This field is required",
6782 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6786 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6788 maxLength : Number.MAX_VALUE,
6790 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6792 minLengthText : "The minimum length for this field is {0}",
6794 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6796 maxLengthText : "The maximum length for this field is {0}",
6800 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6801 * If available, this function will be called only after the basic validators all return true, and will be passed the
6802 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6806 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6807 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6808 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6812 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6835 formatedValue : false,
6837 parentLabelAlign : function()
6840 while (parent.parent()) {
6841 parent = parent.parent();
6842 if (typeof(parent.labelAlign) !='undefined') {
6843 return parent.labelAlign;
6850 getAutoCreate : function(){
6852 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6858 if(this.inputType != 'hidden'){
6859 cfg.cls = 'form-group' //input-group
6865 type : this.inputType,
6867 cls : 'form-control',
6868 placeholder : this.placeholder || ''
6873 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6876 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6877 input.maxLength = this.maxLength;
6880 if (this.disabled) {
6881 input.disabled=true;
6884 if (this.readOnly) {
6885 input.readonly=true;
6889 input.name = this.name;
6892 input.cls += ' input-' + this.size;
6895 ['xs','sm','md','lg'].map(function(size){
6896 if (settings[size]) {
6897 cfg.cls += ' col-' + size + '-' + settings[size];
6901 var inputblock = input;
6903 if (this.before || this.after) {
6906 cls : 'input-group',
6909 if (this.before && typeof(this.before) == 'string') {
6911 inputblock.cn.push({
6913 cls : 'roo-input-before input-group-addon',
6917 if (this.before && typeof(this.before) == 'object') {
6918 this.before = Roo.factory(this.before);
6919 Roo.log(this.before);
6920 inputblock.cn.push({
6922 cls : 'roo-input-before input-group-' +
6923 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6927 inputblock.cn.push(input);
6929 if (this.after && typeof(this.after) == 'string') {
6930 inputblock.cn.push({
6932 cls : 'roo-input-after input-group-addon',
6936 if (this.after && typeof(this.after) == 'object') {
6937 this.after = Roo.factory(this.after);
6938 Roo.log(this.after);
6939 inputblock.cn.push({
6941 cls : 'roo-input-after input-group-' +
6942 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6947 if (align ==='left' && this.fieldLabel.length) {
6948 Roo.log("left and has label");
6954 cls : 'control-label col-sm-' + this.labelWidth,
6955 html : this.fieldLabel
6959 cls : "col-sm-" + (12 - this.labelWidth),
6966 } else if ( this.fieldLabel.length) {
6972 //cls : 'input-group-addon',
6973 html : this.fieldLabel
6983 Roo.log(" no label && no align");
6992 Roo.log('input-parentType: ' + this.parentType);
6994 if (this.parentType === 'Navbar' && this.parent().bar) {
6995 cfg.cls += ' navbar-form';
7003 * return the real input element.
7005 inputEl: function ()
7007 return this.el.select('input.form-control',true).first();
7009 setDisabled : function(v)
7011 var i = this.inputEl().dom;
7013 i.removeAttribute('disabled');
7017 i.setAttribute('disabled','true');
7019 initEvents : function()
7022 this.inputEl().on("keydown" , this.fireKey, this);
7023 this.inputEl().on("focus", this.onFocus, this);
7024 this.inputEl().on("blur", this.onBlur, this);
7026 this.inputEl().relayEvent('keyup', this);
7028 // reference to original value for reset
7029 this.originalValue = this.getValue();
7030 //Roo.form.TextField.superclass.initEvents.call(this);
7031 if(this.validationEvent == 'keyup'){
7032 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7033 this.inputEl().on('keyup', this.filterValidation, this);
7035 else if(this.validationEvent !== false){
7036 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7039 if(this.selectOnFocus){
7040 this.on("focus", this.preFocus, this);
7043 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7044 this.inputEl().on("keypress", this.filterKeys, this);
7047 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7048 this.el.on("click", this.autoSize, this);
7051 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7052 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7055 if (typeof(this.before) == 'object') {
7056 this.before.render(this.el.select('.roo-input-before',true).first());
7058 if (typeof(this.after) == 'object') {
7059 this.after.render(this.el.select('.roo-input-after',true).first());
7064 filterValidation : function(e){
7065 if(!e.isNavKeyPress()){
7066 this.validationTask.delay(this.validationDelay);
7070 * Validates the field value
7071 * @return {Boolean} True if the value is valid, else false
7073 validate : function(){
7074 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7075 if(this.disabled || this.validateValue(this.getRawValue())){
7076 this.clearInvalid();
7084 * Validates a value according to the field's validation rules and marks the field as invalid
7085 * if the validation fails
7086 * @param {Mixed} value The value to validate
7087 * @return {Boolean} True if the value is valid, else false
7089 validateValue : function(value){
7090 if(value.length < 1) { // if it's blank
7091 if(this.allowBlank){
7092 this.clearInvalid();
7095 this.markInvalid(this.blankText);
7099 if(value.length < this.minLength){
7100 this.markInvalid(String.format(this.minLengthText, this.minLength));
7103 if(value.length > this.maxLength){
7104 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7108 var vt = Roo.form.VTypes;
7109 if(!vt[this.vtype](value, this)){
7110 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7114 if(typeof this.validator == "function"){
7115 var msg = this.validator(value);
7117 this.markInvalid(msg);
7121 if(this.regex && !this.regex.test(value)){
7122 this.markInvalid(this.regexText);
7131 fireKey : function(e){
7132 //Roo.log('field ' + e.getKey());
7133 if(e.isNavKeyPress()){
7134 this.fireEvent("specialkey", this, e);
7137 focus : function (selectText){
7139 this.inputEl().focus();
7140 if(selectText === true){
7141 this.inputEl().dom.select();
7147 onFocus : function(){
7148 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7149 // this.el.addClass(this.focusClass);
7152 this.hasFocus = true;
7153 this.startValue = this.getValue();
7154 this.fireEvent("focus", this);
7158 beforeBlur : Roo.emptyFn,
7162 onBlur : function(){
7164 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7165 //this.el.removeClass(this.focusClass);
7167 this.hasFocus = false;
7168 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7171 var v = this.getValue();
7172 if(String(v) !== String(this.startValue)){
7173 this.fireEvent('change', this, v, this.startValue);
7175 this.fireEvent("blur", this);
7179 * Resets the current field value to the originally loaded value and clears any validation messages
7182 this.setValue(this.originalValue);
7183 this.clearInvalid();
7186 * Returns the name of the field
7187 * @return {Mixed} name The name field
7189 getName: function(){
7193 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7194 * @return {Mixed} value The field value
7196 getValue : function(){
7198 var v = this.inputEl().getValue();
7203 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7204 * @return {Mixed} value The field value
7206 getRawValue : function(){
7207 var v = this.inputEl().getValue();
7213 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7214 * @param {Mixed} value The value to set
7216 setRawValue : function(v){
7217 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7220 selectText : function(start, end){
7221 var v = this.getRawValue();
7223 start = start === undefined ? 0 : start;
7224 end = end === undefined ? v.length : end;
7225 var d = this.inputEl().dom;
7226 if(d.setSelectionRange){
7227 d.setSelectionRange(start, end);
7228 }else if(d.createTextRange){
7229 var range = d.createTextRange();
7230 range.moveStart("character", start);
7231 range.moveEnd("character", v.length-end);
7238 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7239 * @param {Mixed} value The value to set
7241 setValue : function(v){
7244 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7250 processValue : function(value){
7251 if(this.stripCharsRe){
7252 var newValue = value.replace(this.stripCharsRe, '');
7253 if(newValue !== value){
7254 this.setRawValue(newValue);
7261 preFocus : function(){
7263 if(this.selectOnFocus){
7264 this.inputEl().dom.select();
7267 filterKeys : function(e){
7269 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7272 var c = e.getCharCode(), cc = String.fromCharCode(c);
7273 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7276 if(!this.maskRe.test(cc)){
7281 * Clear any invalid styles/messages for this field
7283 clearInvalid : function(){
7285 if(!this.el || this.preventMark){ // not rendered
7288 this.el.removeClass(this.invalidClass);
7290 switch(this.msgTarget){
7292 this.el.dom.qtip = '';
7295 this.el.dom.title = '';
7299 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7304 this.errorIcon.dom.qtip = '';
7305 this.errorIcon.hide();
7306 this.un('resize', this.alignErrorIcon, this);
7310 var t = Roo.getDom(this.msgTarget);
7312 t.style.display = 'none';
7316 this.fireEvent('valid', this);
7319 * Mark this field as invalid
7320 * @param {String} msg The validation message
7322 markInvalid : function(msg){
7323 if(!this.el || this.preventMark){ // not rendered
7326 this.el.addClass(this.invalidClass);
7328 msg = msg || this.invalidText;
7329 switch(this.msgTarget){
7331 this.el.dom.qtip = msg;
7332 this.el.dom.qclass = 'x-form-invalid-tip';
7333 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7334 Roo.QuickTips.enable();
7338 this.el.dom.title = msg;
7342 var elp = this.el.findParent('.x-form-element', 5, true);
7343 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7344 this.errorEl.setWidth(elp.getWidth(true)-20);
7346 this.errorEl.update(msg);
7347 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7350 if(!this.errorIcon){
7351 var elp = this.el.findParent('.x-form-element', 5, true);
7352 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7354 this.alignErrorIcon();
7355 this.errorIcon.dom.qtip = msg;
7356 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7357 this.errorIcon.show();
7358 this.on('resize', this.alignErrorIcon, this);
7361 var t = Roo.getDom(this.msgTarget);
7363 t.style.display = this.msgDisplay;
7367 this.fireEvent('invalid', this, msg);
7370 SafariOnKeyDown : function(event)
7372 // this is a workaround for a password hang bug on chrome/ webkit.
7374 var isSelectAll = false;
7376 if(this.inputEl().dom.selectionEnd > 0){
7377 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7379 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7380 event.preventDefault();
7385 if(isSelectAll){ // backspace and delete key
7387 event.preventDefault();
7388 // this is very hacky as keydown always get's upper case.
7390 var cc = String.fromCharCode(event.getCharCode());
7391 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7395 adjustWidth : function(tag, w){
7396 tag = tag.toLowerCase();
7397 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7398 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7402 if(tag == 'textarea'){
7405 }else if(Roo.isOpera){
7409 if(tag == 'textarea'){
7428 * @class Roo.bootstrap.TextArea
7429 * @extends Roo.bootstrap.Input
7430 * Bootstrap TextArea class
7431 * @cfg {Number} cols Specifies the visible width of a text area
7432 * @cfg {Number} rows Specifies the visible number of lines in a text area
7433 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7434 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7435 * @cfg {string} html text
7438 * Create a new TextArea
7439 * @param {Object} config The config object
7442 Roo.bootstrap.TextArea = function(config){
7443 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7447 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7457 getAutoCreate : function(){
7459 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7470 value : this.value || '',
7471 html: this.html || '',
7472 cls : 'form-control',
7473 placeholder : this.placeholder || ''
7477 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7478 input.maxLength = this.maxLength;
7482 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7486 input.cols = this.cols;
7489 if (this.readOnly) {
7490 input.readonly = true;
7494 input.name = this.name;
7498 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7502 ['xs','sm','md','lg'].map(function(size){
7503 if (settings[size]) {
7504 cfg.cls += ' col-' + size + '-' + settings[size];
7508 var inputblock = input;
7510 if (this.before || this.after) {
7513 cls : 'input-group',
7517 inputblock.cn.push({
7519 cls : 'input-group-addon',
7523 inputblock.cn.push(input);
7525 inputblock.cn.push({
7527 cls : 'input-group-addon',
7534 if (align ==='left' && this.fieldLabel.length) {
7535 Roo.log("left and has label");
7541 cls : 'control-label col-sm-' + this.labelWidth,
7542 html : this.fieldLabel
7546 cls : "col-sm-" + (12 - this.labelWidth),
7553 } else if ( this.fieldLabel.length) {
7559 //cls : 'input-group-addon',
7560 html : this.fieldLabel
7570 Roo.log(" no label && no align");
7580 if (this.disabled) {
7581 input.disabled=true;
7588 * return the real textarea element.
7590 inputEl: function ()
7592 return this.el.select('textarea.form-control',true).first();
7600 * trigger field - base class for combo..
7605 * @class Roo.bootstrap.TriggerField
7606 * @extends Roo.bootstrap.Input
7607 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7608 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7609 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7610 * for which you can provide a custom implementation. For example:
7612 var trigger = new Roo.bootstrap.TriggerField();
7613 trigger.onTriggerClick = myTriggerFn;
7614 trigger.applyTo('my-field');
7617 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7618 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7619 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7620 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7622 * Create a new TriggerField.
7623 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7624 * to the base TextField)
7626 Roo.bootstrap.TriggerField = function(config){
7627 this.mimicing = false;
7628 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7631 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7633 * @cfg {String} triggerClass A CSS class to apply to the trigger
7636 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7640 /** @cfg {Boolean} grow @hide */
7641 /** @cfg {Number} growMin @hide */
7642 /** @cfg {Number} growMax @hide */
7648 autoSize: Roo.emptyFn,
7655 actionMode : 'wrap',
7659 getAutoCreate : function(){
7661 var parent = this.parent();
7663 var align = this.labelAlign || this.parentLabelAlign();
7668 cls: 'form-group' //input-group
7675 type : this.inputType,
7676 cls : 'form-control',
7677 autocomplete: 'off',
7678 placeholder : this.placeholder || ''
7682 input.name = this.name;
7685 input.cls += ' input-' + this.size;
7688 if (this.disabled) {
7689 input.disabled=true;
7692 var inputblock = input;
7694 if (this.before || this.after) {
7697 cls : 'input-group',
7701 inputblock.cn.push({
7703 cls : 'input-group-addon',
7707 inputblock.cn.push(input);
7709 inputblock.cn.push({
7711 cls : 'input-group-addon',
7724 cls: 'form-hidden-field'
7732 Roo.log('multiple');
7740 cls: 'form-hidden-field'
7744 cls: 'select2-choices',
7748 cls: 'select2-search-field',
7761 cls: 'select2-container input-group',
7766 cls: 'typeahead typeahead-long dropdown-menu',
7767 style: 'display:none'
7775 cls : 'input-group-addon btn dropdown-toggle',
7783 cls: 'combobox-clear',
7797 combobox.cls += ' select2-container-multi';
7800 if (align ==='left' && this.fieldLabel.length) {
7802 Roo.log("left and has label");
7808 cls : 'control-label col-sm-' + this.labelWidth,
7809 html : this.fieldLabel
7813 cls : "col-sm-" + (12 - this.labelWidth),
7820 } else if ( this.fieldLabel.length) {
7826 //cls : 'input-group-addon',
7827 html : this.fieldLabel
7837 Roo.log(" no label && no align");
7844 ['xs','sm','md','lg'].map(function(size){
7845 if (settings[size]) {
7846 cfg.cls += ' col-' + size + '-' + settings[size];
7857 onResize : function(w, h){
7858 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7859 // if(typeof w == 'number'){
7860 // var x = w - this.trigger.getWidth();
7861 // this.inputEl().setWidth(this.adjustWidth('input', x));
7862 // this.trigger.setStyle('left', x+'px');
7867 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7870 getResizeEl : function(){
7871 return this.inputEl();
7875 getPositionEl : function(){
7876 return this.inputEl();
7880 alignErrorIcon : function(){
7881 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7885 initEvents : function(){
7887 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7888 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7890 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7891 if(this.hideTrigger){
7892 this.trigger.setDisplayed(false);
7894 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7898 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7901 //this.trigger.addClassOnOver('x-form-trigger-over');
7902 //this.trigger.addClassOnClick('x-form-trigger-click');
7905 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7910 initTrigger : function(){
7915 onDestroy : function(){
7917 this.trigger.removeAllListeners();
7918 // this.trigger.remove();
7921 // this.wrap.remove();
7923 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7927 onFocus : function(){
7928 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7931 this.wrap.addClass('x-trigger-wrap-focus');
7932 this.mimicing = true;
7933 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7934 if(this.monitorTab){
7935 this.el.on("keydown", this.checkTab, this);
7942 checkTab : function(e){
7943 if(e.getKey() == e.TAB){
7949 onBlur : function(){
7954 mimicBlur : function(e, t){
7956 if(!this.wrap.contains(t) && this.validateBlur()){
7963 triggerBlur : function(){
7964 this.mimicing = false;
7965 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7966 if(this.monitorTab){
7967 this.el.un("keydown", this.checkTab, this);
7969 //this.wrap.removeClass('x-trigger-wrap-focus');
7970 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7974 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7975 validateBlur : function(e, t){
7980 onDisable : function(){
7981 this.inputEl().dom.disabled = true;
7982 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7984 // this.wrap.addClass('x-item-disabled');
7989 onEnable : function(){
7990 this.inputEl().dom.disabled = false;
7991 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7993 // this.el.removeClass('x-item-disabled');
7998 onShow : function(){
7999 var ae = this.getActionEl();
8002 ae.dom.style.display = '';
8003 ae.dom.style.visibility = 'visible';
8009 onHide : function(){
8010 var ae = this.getActionEl();
8011 ae.dom.style.display = 'none';
8015 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8016 * by an implementing function.
8018 * @param {EventObject} e
8020 onTriggerClick : Roo.emptyFn
8024 * Ext JS Library 1.1.1
8025 * Copyright(c) 2006-2007, Ext JS, LLC.
8027 * Originally Released Under LGPL - original licence link has changed is not relivant.
8030 * <script type="text/javascript">
8035 * @class Roo.data.SortTypes
8037 * Defines the default sorting (casting?) comparison functions used when sorting data.
8039 Roo.data.SortTypes = {
8041 * Default sort that does nothing
8042 * @param {Mixed} s The value being converted
8043 * @return {Mixed} The comparison value
8050 * The regular expression used to strip tags
8054 stripTagsRE : /<\/?[^>]+>/gi,
8057 * Strips all HTML tags to sort on text only
8058 * @param {Mixed} s The value being converted
8059 * @return {String} The comparison value
8061 asText : function(s){
8062 return String(s).replace(this.stripTagsRE, "");
8066 * Strips all HTML tags to sort on text only - Case insensitive
8067 * @param {Mixed} s The value being converted
8068 * @return {String} The comparison value
8070 asUCText : function(s){
8071 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8075 * Case insensitive string
8076 * @param {Mixed} s The value being converted
8077 * @return {String} The comparison value
8079 asUCString : function(s) {
8080 return String(s).toUpperCase();
8085 * @param {Mixed} s The value being converted
8086 * @return {Number} The comparison value
8088 asDate : function(s) {
8092 if(s instanceof Date){
8095 return Date.parse(String(s));
8100 * @param {Mixed} s The value being converted
8101 * @return {Float} The comparison value
8103 asFloat : function(s) {
8104 var val = parseFloat(String(s).replace(/,/g, ""));
8105 if(isNaN(val)) val = 0;
8111 * @param {Mixed} s The value being converted
8112 * @return {Number} The comparison value
8114 asInt : function(s) {
8115 var val = parseInt(String(s).replace(/,/g, ""));
8116 if(isNaN(val)) val = 0;
8121 * Ext JS Library 1.1.1
8122 * Copyright(c) 2006-2007, Ext JS, LLC.
8124 * Originally Released Under LGPL - original licence link has changed is not relivant.
8127 * <script type="text/javascript">
8131 * @class Roo.data.Record
8132 * Instances of this class encapsulate both record <em>definition</em> information, and record
8133 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8134 * to access Records cached in an {@link Roo.data.Store} object.<br>
8136 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8137 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8140 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8142 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8143 * {@link #create}. The parameters are the same.
8144 * @param {Array} data An associative Array of data values keyed by the field name.
8145 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8146 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8147 * not specified an integer id is generated.
8149 Roo.data.Record = function(data, id){
8150 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8155 * Generate a constructor for a specific record layout.
8156 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8157 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8158 * Each field definition object may contain the following properties: <ul>
8159 * <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,
8160 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8161 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8162 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8163 * is being used, then this is a string containing the javascript expression to reference the data relative to
8164 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8165 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8166 * this may be omitted.</p></li>
8167 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8168 * <ul><li>auto (Default, implies no conversion)</li>
8173 * <li>date</li></ul></p></li>
8174 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8175 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8176 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8177 * by the Reader into an object that will be stored in the Record. It is passed the
8178 * following parameters:<ul>
8179 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8181 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8183 * <br>usage:<br><pre><code>
8184 var TopicRecord = Roo.data.Record.create(
8185 {name: 'title', mapping: 'topic_title'},
8186 {name: 'author', mapping: 'username'},
8187 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8188 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8189 {name: 'lastPoster', mapping: 'user2'},
8190 {name: 'excerpt', mapping: 'post_text'}
8193 var myNewRecord = new TopicRecord({
8194 title: 'Do my job please',
8197 lastPost: new Date(),
8198 lastPoster: 'Animal',
8199 excerpt: 'No way dude!'
8201 myStore.add(myNewRecord);
8206 Roo.data.Record.create = function(o){
8208 f.superclass.constructor.apply(this, arguments);
8210 Roo.extend(f, Roo.data.Record);
8211 var p = f.prototype;
8212 p.fields = new Roo.util.MixedCollection(false, function(field){
8215 for(var i = 0, len = o.length; i < len; i++){
8216 p.fields.add(new Roo.data.Field(o[i]));
8218 f.getField = function(name){
8219 return p.fields.get(name);
8224 Roo.data.Record.AUTO_ID = 1000;
8225 Roo.data.Record.EDIT = 'edit';
8226 Roo.data.Record.REJECT = 'reject';
8227 Roo.data.Record.COMMIT = 'commit';
8229 Roo.data.Record.prototype = {
8231 * Readonly flag - true if this record has been modified.
8240 join : function(store){
8245 * Set the named field to the specified value.
8246 * @param {String} name The name of the field to set.
8247 * @param {Object} value The value to set the field to.
8249 set : function(name, value){
8250 if(this.data[name] == value){
8257 if(typeof this.modified[name] == 'undefined'){
8258 this.modified[name] = this.data[name];
8260 this.data[name] = value;
8261 if(!this.editing && this.store){
8262 this.store.afterEdit(this);
8267 * Get the value of the named field.
8268 * @param {String} name The name of the field to get the value of.
8269 * @return {Object} The value of the field.
8271 get : function(name){
8272 return this.data[name];
8276 beginEdit : function(){
8277 this.editing = true;
8282 cancelEdit : function(){
8283 this.editing = false;
8284 delete this.modified;
8288 endEdit : function(){
8289 this.editing = false;
8290 if(this.dirty && this.store){
8291 this.store.afterEdit(this);
8296 * Usually called by the {@link Roo.data.Store} which owns the Record.
8297 * Rejects all changes made to the Record since either creation, or the last commit operation.
8298 * Modified fields are reverted to their original values.
8300 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8301 * of reject operations.
8303 reject : function(){
8304 var m = this.modified;
8306 if(typeof m[n] != "function"){
8307 this.data[n] = m[n];
8311 delete this.modified;
8312 this.editing = false;
8314 this.store.afterReject(this);
8319 * Usually called by the {@link Roo.data.Store} which owns the Record.
8320 * Commits all changes made to the Record since either creation, or the last commit operation.
8322 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8323 * of commit operations.
8325 commit : function(){
8327 delete this.modified;
8328 this.editing = false;
8330 this.store.afterCommit(this);
8335 hasError : function(){
8336 return this.error != null;
8340 clearError : function(){
8345 * Creates a copy of this record.
8346 * @param {String} id (optional) A new record id if you don't want to use this record's id
8349 copy : function(newId) {
8350 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8354 * Ext JS Library 1.1.1
8355 * Copyright(c) 2006-2007, Ext JS, LLC.
8357 * Originally Released Under LGPL - original licence link has changed is not relivant.
8360 * <script type="text/javascript">
8366 * @class Roo.data.Store
8367 * @extends Roo.util.Observable
8368 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8369 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8371 * 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
8372 * has no knowledge of the format of the data returned by the Proxy.<br>
8374 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8375 * instances from the data object. These records are cached and made available through accessor functions.
8377 * Creates a new Store.
8378 * @param {Object} config A config object containing the objects needed for the Store to access data,
8379 * and read the data into Records.
8381 Roo.data.Store = function(config){
8382 this.data = new Roo.util.MixedCollection(false);
8383 this.data.getKey = function(o){
8386 this.baseParams = {};
8393 "multisort" : "_multisort"
8396 if(config && config.data){
8397 this.inlineData = config.data;
8401 Roo.apply(this, config);
8403 if(this.reader){ // reader passed
8404 this.reader = Roo.factory(this.reader, Roo.data);
8405 this.reader.xmodule = this.xmodule || false;
8406 if(!this.recordType){
8407 this.recordType = this.reader.recordType;
8409 if(this.reader.onMetaChange){
8410 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8414 if(this.recordType){
8415 this.fields = this.recordType.prototype.fields;
8421 * @event datachanged
8422 * Fires when the data cache has changed, and a widget which is using this Store
8423 * as a Record cache should refresh its view.
8424 * @param {Store} this
8429 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8430 * @param {Store} this
8431 * @param {Object} meta The JSON metadata
8436 * Fires when Records have been added to the Store
8437 * @param {Store} this
8438 * @param {Roo.data.Record[]} records The array of Records added
8439 * @param {Number} index The index at which the record(s) were added
8444 * Fires when a Record has been removed from the Store
8445 * @param {Store} this
8446 * @param {Roo.data.Record} record The Record that was removed
8447 * @param {Number} index The index at which the record was removed
8452 * Fires when a Record has been updated
8453 * @param {Store} this
8454 * @param {Roo.data.Record} record The Record that was updated
8455 * @param {String} operation The update operation being performed. Value may be one of:
8457 Roo.data.Record.EDIT
8458 Roo.data.Record.REJECT
8459 Roo.data.Record.COMMIT
8465 * Fires when the data cache has been cleared.
8466 * @param {Store} this
8471 * Fires before a request is made for a new data object. If the beforeload handler returns false
8472 * the load action will be canceled.
8473 * @param {Store} this
8474 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8478 * @event beforeloadadd
8479 * Fires after a new set of Records has been loaded.
8480 * @param {Store} this
8481 * @param {Roo.data.Record[]} records The Records that were loaded
8482 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8484 beforeloadadd : true,
8487 * Fires after a new set of Records has been loaded, before they are added to the store.
8488 * @param {Store} this
8489 * @param {Roo.data.Record[]} records The Records that were loaded
8490 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8491 * @params {Object} return from reader
8495 * @event loadexception
8496 * Fires if an exception occurs in the Proxy during loading.
8497 * Called with the signature of the Proxy's "loadexception" event.
8498 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8501 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8502 * @param {Object} load options
8503 * @param {Object} jsonData from your request (normally this contains the Exception)
8505 loadexception : true
8509 this.proxy = Roo.factory(this.proxy, Roo.data);
8510 this.proxy.xmodule = this.xmodule || false;
8511 this.relayEvents(this.proxy, ["loadexception"]);
8513 this.sortToggle = {};
8514 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8516 Roo.data.Store.superclass.constructor.call(this);
8518 if(this.inlineData){
8519 this.loadData(this.inlineData);
8520 delete this.inlineData;
8524 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8526 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8527 * without a remote query - used by combo/forms at present.
8531 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8534 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8537 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8538 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8541 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8542 * on any HTTP request
8545 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8548 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8552 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8553 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8558 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8559 * loaded or when a record is removed. (defaults to false).
8561 pruneModifiedRecords : false,
8567 * Add Records to the Store and fires the add event.
8568 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8570 add : function(records){
8571 records = [].concat(records);
8572 for(var i = 0, len = records.length; i < len; i++){
8573 records[i].join(this);
8575 var index = this.data.length;
8576 this.data.addAll(records);
8577 this.fireEvent("add", this, records, index);
8581 * Remove a Record from the Store and fires the remove event.
8582 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8584 remove : function(record){
8585 var index = this.data.indexOf(record);
8586 this.data.removeAt(index);
8587 if(this.pruneModifiedRecords){
8588 this.modified.remove(record);
8590 this.fireEvent("remove", this, record, index);
8594 * Remove all Records from the Store and fires the clear event.
8596 removeAll : function(){
8598 if(this.pruneModifiedRecords){
8601 this.fireEvent("clear", this);
8605 * Inserts Records to the Store at the given index and fires the add event.
8606 * @param {Number} index The start index at which to insert the passed Records.
8607 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8609 insert : function(index, records){
8610 records = [].concat(records);
8611 for(var i = 0, len = records.length; i < len; i++){
8612 this.data.insert(index, records[i]);
8613 records[i].join(this);
8615 this.fireEvent("add", this, records, index);
8619 * Get the index within the cache of the passed Record.
8620 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8621 * @return {Number} The index of the passed Record. Returns -1 if not found.
8623 indexOf : function(record){
8624 return this.data.indexOf(record);
8628 * Get the index within the cache of the Record with the passed id.
8629 * @param {String} id The id of the Record to find.
8630 * @return {Number} The index of the Record. Returns -1 if not found.
8632 indexOfId : function(id){
8633 return this.data.indexOfKey(id);
8637 * Get the Record with the specified id.
8638 * @param {String} id The id of the Record to find.
8639 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8641 getById : function(id){
8642 return this.data.key(id);
8646 * Get the Record at the specified index.
8647 * @param {Number} index The index of the Record to find.
8648 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8650 getAt : function(index){
8651 return this.data.itemAt(index);
8655 * Returns a range of Records between specified indices.
8656 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8657 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8658 * @return {Roo.data.Record[]} An array of Records
8660 getRange : function(start, end){
8661 return this.data.getRange(start, end);
8665 storeOptions : function(o){
8666 o = Roo.apply({}, o);
8669 this.lastOptions = o;
8673 * Loads the Record cache from the configured Proxy using the configured Reader.
8675 * If using remote paging, then the first load call must specify the <em>start</em>
8676 * and <em>limit</em> properties in the options.params property to establish the initial
8677 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8679 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8680 * and this call will return before the new data has been loaded. Perform any post-processing
8681 * in a callback function, or in a "load" event handler.</strong>
8683 * @param {Object} options An object containing properties which control loading options:<ul>
8684 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8685 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8686 * passed the following arguments:<ul>
8687 * <li>r : Roo.data.Record[]</li>
8688 * <li>options: Options object from the load call</li>
8689 * <li>success: Boolean success indicator</li></ul></li>
8690 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8691 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8694 load : function(options){
8695 options = options || {};
8696 if(this.fireEvent("beforeload", this, options) !== false){
8697 this.storeOptions(options);
8698 var p = Roo.apply(options.params || {}, this.baseParams);
8699 // if meta was not loaded from remote source.. try requesting it.
8700 if (!this.reader.metaFromRemote) {
8703 if(this.sortInfo && this.remoteSort){
8704 var pn = this.paramNames;
8705 p[pn["sort"]] = this.sortInfo.field;
8706 p[pn["dir"]] = this.sortInfo.direction;
8708 if (this.multiSort) {
8709 var pn = this.paramNames;
8710 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8713 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8718 * Reloads the Record cache from the configured Proxy using the configured Reader and
8719 * the options from the last load operation performed.
8720 * @param {Object} options (optional) An object containing properties which may override the options
8721 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8722 * the most recently used options are reused).
8724 reload : function(options){
8725 this.load(Roo.applyIf(options||{}, this.lastOptions));
8729 // Called as a callback by the Reader during a load operation.
8730 loadRecords : function(o, options, success){
8731 if(!o || success === false){
8732 if(success !== false){
8733 this.fireEvent("load", this, [], options, o);
8735 if(options.callback){
8736 options.callback.call(options.scope || this, [], options, false);
8740 // if data returned failure - throw an exception.
8741 if (o.success === false) {
8742 // show a message if no listener is registered.
8743 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8744 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8746 // loadmask wil be hooked into this..
8747 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8750 var r = o.records, t = o.totalRecords || r.length;
8752 this.fireEvent("beforeloadadd", this, r, options, o);
8754 if(!options || options.add !== true){
8755 if(this.pruneModifiedRecords){
8758 for(var i = 0, len = r.length; i < len; i++){
8762 this.data = this.snapshot;
8763 delete this.snapshot;
8766 this.data.addAll(r);
8767 this.totalLength = t;
8769 this.fireEvent("datachanged", this);
8771 this.totalLength = Math.max(t, this.data.length+r.length);
8774 this.fireEvent("load", this, r, options, o);
8775 if(options.callback){
8776 options.callback.call(options.scope || this, r, options, true);
8782 * Loads data from a passed data block. A Reader which understands the format of the data
8783 * must have been configured in the constructor.
8784 * @param {Object} data The data block from which to read the Records. The format of the data expected
8785 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8786 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8788 loadData : function(o, append){
8789 var r = this.reader.readRecords(o);
8790 this.loadRecords(r, {add: append}, true);
8794 * Gets the number of cached records.
8796 * <em>If using paging, this may not be the total size of the dataset. If the data object
8797 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8798 * the data set size</em>
8800 getCount : function(){
8801 return this.data.length || 0;
8805 * Gets the total number of records in the dataset as returned by the server.
8807 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8808 * the dataset size</em>
8810 getTotalCount : function(){
8811 return this.totalLength || 0;
8815 * Returns the sort state of the Store as an object with two properties:
8817 field {String} The name of the field by which the Records are sorted
8818 direction {String} The sort order, "ASC" or "DESC"
8821 getSortState : function(){
8822 return this.sortInfo;
8826 applySort : function(){
8827 if(this.sortInfo && !this.remoteSort){
8828 var s = this.sortInfo, f = s.field;
8829 var st = this.fields.get(f).sortType;
8830 var fn = function(r1, r2){
8831 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8832 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8834 this.data.sort(s.direction, fn);
8835 if(this.snapshot && this.snapshot != this.data){
8836 this.snapshot.sort(s.direction, fn);
8842 * Sets the default sort column and order to be used by the next load operation.
8843 * @param {String} fieldName The name of the field to sort by.
8844 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8846 setDefaultSort : function(field, dir){
8847 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8852 * If remote sorting is used, the sort is performed on the server, and the cache is
8853 * reloaded. If local sorting is used, the cache is sorted internally.
8854 * @param {String} fieldName The name of the field to sort by.
8855 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8857 sort : function(fieldName, dir){
8858 var f = this.fields.get(fieldName);
8860 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8862 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8863 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8868 this.sortToggle[f.name] = dir;
8869 this.sortInfo = {field: f.name, direction: dir};
8870 if(!this.remoteSort){
8872 this.fireEvent("datachanged", this);
8874 this.load(this.lastOptions);
8879 * Calls the specified function for each of the Records in the cache.
8880 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8881 * Returning <em>false</em> aborts and exits the iteration.
8882 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8884 each : function(fn, scope){
8885 this.data.each(fn, scope);
8889 * Gets all records modified since the last commit. Modified records are persisted across load operations
8890 * (e.g., during paging).
8891 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8893 getModifiedRecords : function(){
8894 return this.modified;
8898 createFilterFn : function(property, value, anyMatch){
8899 if(!value.exec){ // not a regex
8900 value = String(value);
8901 if(value.length == 0){
8904 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8907 return value.test(r.data[property]);
8912 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8913 * @param {String} property A field on your records
8914 * @param {Number} start The record index to start at (defaults to 0)
8915 * @param {Number} end The last record index to include (defaults to length - 1)
8916 * @return {Number} The sum
8918 sum : function(property, start, end){
8919 var rs = this.data.items, v = 0;
8921 end = (end || end === 0) ? end : rs.length-1;
8923 for(var i = start; i <= end; i++){
8924 v += (rs[i].data[property] || 0);
8930 * Filter the records by a specified property.
8931 * @param {String} field A field on your records
8932 * @param {String/RegExp} value Either a string that the field
8933 * should start with or a RegExp to test against the field
8934 * @param {Boolean} anyMatch True to match any part not just the beginning
8936 filter : function(property, value, anyMatch){
8937 var fn = this.createFilterFn(property, value, anyMatch);
8938 return fn ? this.filterBy(fn) : this.clearFilter();
8942 * Filter by a function. The specified function will be called with each
8943 * record in this data source. If the function returns true the record is included,
8944 * otherwise it is filtered.
8945 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8946 * @param {Object} scope (optional) The scope of the function (defaults to this)
8948 filterBy : function(fn, scope){
8949 this.snapshot = this.snapshot || this.data;
8950 this.data = this.queryBy(fn, scope||this);
8951 this.fireEvent("datachanged", this);
8955 * Query the records by a specified property.
8956 * @param {String} field A field on your records
8957 * @param {String/RegExp} value Either a string that the field
8958 * should start with or a RegExp to test against the field
8959 * @param {Boolean} anyMatch True to match any part not just the beginning
8960 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8962 query : function(property, value, anyMatch){
8963 var fn = this.createFilterFn(property, value, anyMatch);
8964 return fn ? this.queryBy(fn) : this.data.clone();
8968 * Query by a function. The specified function will be called with each
8969 * record in this data source. If the function returns true the record is included
8971 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8972 * @param {Object} scope (optional) The scope of the function (defaults to this)
8973 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8975 queryBy : function(fn, scope){
8976 var data = this.snapshot || this.data;
8977 return data.filterBy(fn, scope||this);
8981 * Collects unique values for a particular dataIndex from this store.
8982 * @param {String} dataIndex The property to collect
8983 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8984 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8985 * @return {Array} An array of the unique values
8987 collect : function(dataIndex, allowNull, bypassFilter){
8988 var d = (bypassFilter === true && this.snapshot) ?
8989 this.snapshot.items : this.data.items;
8990 var v, sv, r = [], l = {};
8991 for(var i = 0, len = d.length; i < len; i++){
8992 v = d[i].data[dataIndex];
8994 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9003 * Revert to a view of the Record cache with no filtering applied.
9004 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9006 clearFilter : function(suppressEvent){
9007 if(this.snapshot && this.snapshot != this.data){
9008 this.data = this.snapshot;
9009 delete this.snapshot;
9010 if(suppressEvent !== true){
9011 this.fireEvent("datachanged", this);
9017 afterEdit : function(record){
9018 if(this.modified.indexOf(record) == -1){
9019 this.modified.push(record);
9021 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9025 afterReject : function(record){
9026 this.modified.remove(record);
9027 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9031 afterCommit : function(record){
9032 this.modified.remove(record);
9033 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9037 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9038 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9040 commitChanges : function(){
9041 var m = this.modified.slice(0);
9043 for(var i = 0, len = m.length; i < len; i++){
9049 * Cancel outstanding changes on all changed records.
9051 rejectChanges : function(){
9052 var m = this.modified.slice(0);
9054 for(var i = 0, len = m.length; i < len; i++){
9059 onMetaChange : function(meta, rtype, o){
9060 this.recordType = rtype;
9061 this.fields = rtype.prototype.fields;
9062 delete this.snapshot;
9063 this.sortInfo = meta.sortInfo || this.sortInfo;
9065 this.fireEvent('metachange', this, this.reader.meta);
9068 moveIndex : function(data, type)
9070 var index = this.indexOf(data);
9072 var newIndex = index + type;
9076 this.insert(newIndex, data);
9081 * Ext JS Library 1.1.1
9082 * Copyright(c) 2006-2007, Ext JS, LLC.
9084 * Originally Released Under LGPL - original licence link has changed is not relivant.
9087 * <script type="text/javascript">
9091 * @class Roo.data.SimpleStore
9092 * @extends Roo.data.Store
9093 * Small helper class to make creating Stores from Array data easier.
9094 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9095 * @cfg {Array} fields An array of field definition objects, or field name strings.
9096 * @cfg {Array} data The multi-dimensional array of data
9098 * @param {Object} config
9100 Roo.data.SimpleStore = function(config){
9101 Roo.data.SimpleStore.superclass.constructor.call(this, {
9103 reader: new Roo.data.ArrayReader({
9106 Roo.data.Record.create(config.fields)
9108 proxy : new Roo.data.MemoryProxy(config.data)
9112 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9114 * Ext JS Library 1.1.1
9115 * Copyright(c) 2006-2007, Ext JS, LLC.
9117 * Originally Released Under LGPL - original licence link has changed is not relivant.
9120 * <script type="text/javascript">
9125 * @extends Roo.data.Store
9126 * @class Roo.data.JsonStore
9127 * Small helper class to make creating Stores for JSON data easier. <br/>
9129 var store = new Roo.data.JsonStore({
9130 url: 'get-images.php',
9132 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9135 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9136 * JsonReader and HttpProxy (unless inline data is provided).</b>
9137 * @cfg {Array} fields An array of field definition objects, or field name strings.
9139 * @param {Object} config
9141 Roo.data.JsonStore = function(c){
9142 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9143 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9144 reader: new Roo.data.JsonReader(c, c.fields)
9147 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9149 * Ext JS Library 1.1.1
9150 * Copyright(c) 2006-2007, Ext JS, LLC.
9152 * Originally Released Under LGPL - original licence link has changed is not relivant.
9155 * <script type="text/javascript">
9159 Roo.data.Field = function(config){
9160 if(typeof config == "string"){
9161 config = {name: config};
9163 Roo.apply(this, config);
9169 var st = Roo.data.SortTypes;
9170 // named sortTypes are supported, here we look them up
9171 if(typeof this.sortType == "string"){
9172 this.sortType = st[this.sortType];
9175 // set default sortType for strings and dates
9179 this.sortType = st.asUCString;
9182 this.sortType = st.asDate;
9185 this.sortType = st.none;
9190 var stripRe = /[\$,%]/g;
9192 // prebuilt conversion function for this field, instead of
9193 // switching every time we're reading a value
9195 var cv, dateFormat = this.dateFormat;
9200 cv = function(v){ return v; };
9203 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9207 return v !== undefined && v !== null && v !== '' ?
9208 parseInt(String(v).replace(stripRe, ""), 10) : '';
9213 return v !== undefined && v !== null && v !== '' ?
9214 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9219 cv = function(v){ return v === true || v === "true" || v == 1; };
9226 if(v instanceof Date){
9230 if(dateFormat == "timestamp"){
9231 return new Date(v*1000);
9233 return Date.parseDate(v, dateFormat);
9235 var parsed = Date.parse(v);
9236 return parsed ? new Date(parsed) : null;
9245 Roo.data.Field.prototype = {
9253 * Ext JS Library 1.1.1
9254 * Copyright(c) 2006-2007, Ext JS, LLC.
9256 * Originally Released Under LGPL - original licence link has changed is not relivant.
9259 * <script type="text/javascript">
9262 // Base class for reading structured data from a data source. This class is intended to be
9263 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9266 * @class Roo.data.DataReader
9267 * Base class for reading structured data from a data source. This class is intended to be
9268 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9271 Roo.data.DataReader = function(meta, recordType){
9275 this.recordType = recordType instanceof Array ?
9276 Roo.data.Record.create(recordType) : recordType;
9279 Roo.data.DataReader.prototype = {
9281 * Create an empty record
9282 * @param {Object} data (optional) - overlay some values
9283 * @return {Roo.data.Record} record created.
9285 newRow : function(d) {
9287 this.recordType.prototype.fields.each(function(c) {
9289 case 'int' : da[c.name] = 0; break;
9290 case 'date' : da[c.name] = new Date(); break;
9291 case 'float' : da[c.name] = 0.0; break;
9292 case 'boolean' : da[c.name] = false; break;
9293 default : da[c.name] = ""; break;
9297 return new this.recordType(Roo.apply(da, d));
9302 * Ext JS Library 1.1.1
9303 * Copyright(c) 2006-2007, Ext JS, LLC.
9305 * Originally Released Under LGPL - original licence link has changed is not relivant.
9308 * <script type="text/javascript">
9312 * @class Roo.data.DataProxy
9313 * @extends Roo.data.Observable
9314 * This class is an abstract base class for implementations which provide retrieval of
9315 * unformatted data objects.<br>
9317 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9318 * (of the appropriate type which knows how to parse the data object) to provide a block of
9319 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9321 * Custom implementations must implement the load method as described in
9322 * {@link Roo.data.HttpProxy#load}.
9324 Roo.data.DataProxy = function(){
9328 * Fires before a network request is made to retrieve a data object.
9329 * @param {Object} This DataProxy object.
9330 * @param {Object} params The params parameter to the load function.
9335 * Fires before the load method's callback is called.
9336 * @param {Object} This DataProxy object.
9337 * @param {Object} o The data object.
9338 * @param {Object} arg The callback argument object passed to the load function.
9342 * @event loadexception
9343 * Fires if an Exception occurs during data retrieval.
9344 * @param {Object} This DataProxy object.
9345 * @param {Object} o The data object.
9346 * @param {Object} arg The callback argument object passed to the load function.
9347 * @param {Object} e The Exception.
9349 loadexception : true
9351 Roo.data.DataProxy.superclass.constructor.call(this);
9354 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9357 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9361 * Ext JS Library 1.1.1
9362 * Copyright(c) 2006-2007, Ext JS, LLC.
9364 * Originally Released Under LGPL - original licence link has changed is not relivant.
9367 * <script type="text/javascript">
9370 * @class Roo.data.MemoryProxy
9371 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9372 * to the Reader when its load method is called.
9374 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9376 Roo.data.MemoryProxy = function(data){
9380 Roo.data.MemoryProxy.superclass.constructor.call(this);
9384 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9386 * Load data from the requested source (in this case an in-memory
9387 * data object passed to the constructor), read the data object into
9388 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9389 * process that block using the passed callback.
9390 * @param {Object} params This parameter is not used by the MemoryProxy class.
9391 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9392 * object into a block of Roo.data.Records.
9393 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9394 * The function must be passed <ul>
9395 * <li>The Record block object</li>
9396 * <li>The "arg" argument from the load function</li>
9397 * <li>A boolean success indicator</li>
9399 * @param {Object} scope The scope in which to call the callback
9400 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9402 load : function(params, reader, callback, scope, arg){
9403 params = params || {};
9406 result = reader.readRecords(this.data);
9408 this.fireEvent("loadexception", this, arg, null, e);
9409 callback.call(scope, null, arg, false);
9412 callback.call(scope, result, arg, true);
9416 update : function(params, records){
9421 * Ext JS Library 1.1.1
9422 * Copyright(c) 2006-2007, Ext JS, LLC.
9424 * Originally Released Under LGPL - original licence link has changed is not relivant.
9427 * <script type="text/javascript">
9430 * @class Roo.data.HttpProxy
9431 * @extends Roo.data.DataProxy
9432 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9433 * configured to reference a certain URL.<br><br>
9435 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9436 * from which the running page was served.<br><br>
9438 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9440 * Be aware that to enable the browser to parse an XML document, the server must set
9441 * the Content-Type header in the HTTP response to "text/xml".
9443 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9444 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9445 * will be used to make the request.
9447 Roo.data.HttpProxy = function(conn){
9448 Roo.data.HttpProxy.superclass.constructor.call(this);
9449 // is conn a conn config or a real conn?
9451 this.useAjax = !conn || !conn.events;
9455 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9456 // thse are take from connection...
9459 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9462 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9463 * extra parameters to each request made by this object. (defaults to undefined)
9466 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9467 * to each request made by this object. (defaults to undefined)
9470 * @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)
9473 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9476 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9482 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9486 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9487 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9488 * a finer-grained basis than the DataProxy events.
9490 getConnection : function(){
9491 return this.useAjax ? Roo.Ajax : this.conn;
9495 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9496 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9497 * process that block using the passed callback.
9498 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9499 * for the request to the remote server.
9500 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9501 * object into a block of Roo.data.Records.
9502 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9503 * The function must be passed <ul>
9504 * <li>The Record block object</li>
9505 * <li>The "arg" argument from the load function</li>
9506 * <li>A boolean success indicator</li>
9508 * @param {Object} scope The scope in which to call the callback
9509 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9511 load : function(params, reader, callback, scope, arg){
9512 if(this.fireEvent("beforeload", this, params) !== false){
9514 params : params || {},
9516 callback : callback,
9521 callback : this.loadResponse,
9525 Roo.applyIf(o, this.conn);
9526 if(this.activeRequest){
9527 Roo.Ajax.abort(this.activeRequest);
9529 this.activeRequest = Roo.Ajax.request(o);
9531 this.conn.request(o);
9534 callback.call(scope||this, null, arg, false);
9539 loadResponse : function(o, success, response){
9540 delete this.activeRequest;
9542 this.fireEvent("loadexception", this, o, response);
9543 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9548 result = o.reader.read(response);
9550 this.fireEvent("loadexception", this, o, response, e);
9551 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9555 this.fireEvent("load", this, o, o.request.arg);
9556 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9560 update : function(dataSet){
9565 updateResponse : function(dataSet){
9570 * Ext JS Library 1.1.1
9571 * Copyright(c) 2006-2007, Ext JS, LLC.
9573 * Originally Released Under LGPL - original licence link has changed is not relivant.
9576 * <script type="text/javascript">
9580 * @class Roo.data.ScriptTagProxy
9581 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9582 * other than the originating domain of the running page.<br><br>
9584 * <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
9585 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9587 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9588 * source code that is used as the source inside a <script> tag.<br><br>
9590 * In order for the browser to process the returned data, the server must wrap the data object
9591 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9592 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9593 * depending on whether the callback name was passed:
9596 boolean scriptTag = false;
9597 String cb = request.getParameter("callback");
9600 response.setContentType("text/javascript");
9602 response.setContentType("application/x-json");
9604 Writer out = response.getWriter();
9606 out.write(cb + "(");
9608 out.print(dataBlock.toJsonString());
9615 * @param {Object} config A configuration object.
9617 Roo.data.ScriptTagProxy = function(config){
9618 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9619 Roo.apply(this, config);
9620 this.head = document.getElementsByTagName("head")[0];
9623 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9625 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9627 * @cfg {String} url The URL from which to request the data object.
9630 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9634 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9635 * the server the name of the callback function set up by the load call to process the returned data object.
9636 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9637 * javascript output which calls this named function passing the data object as its only parameter.
9639 callbackParam : "callback",
9641 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9642 * name to the request.
9647 * Load data from the configured URL, read the data object into
9648 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9649 * process that block using the passed callback.
9650 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9651 * for the request to the remote server.
9652 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9653 * object into a block of Roo.data.Records.
9654 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9655 * The function must be passed <ul>
9656 * <li>The Record block object</li>
9657 * <li>The "arg" argument from the load function</li>
9658 * <li>A boolean success indicator</li>
9660 * @param {Object} scope The scope in which to call the callback
9661 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9663 load : function(params, reader, callback, scope, arg){
9664 if(this.fireEvent("beforeload", this, params) !== false){
9666 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9669 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9671 url += "&_dc=" + (new Date().getTime());
9673 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9676 cb : "stcCallback"+transId,
9677 scriptId : "stcScript"+transId,
9681 callback : callback,
9687 window[trans.cb] = function(o){
9688 conn.handleResponse(o, trans);
9691 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9693 if(this.autoAbort !== false){
9697 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9699 var script = document.createElement("script");
9700 script.setAttribute("src", url);
9701 script.setAttribute("type", "text/javascript");
9702 script.setAttribute("id", trans.scriptId);
9703 this.head.appendChild(script);
9707 callback.call(scope||this, null, arg, false);
9712 isLoading : function(){
9713 return this.trans ? true : false;
9717 * Abort the current server request.
9720 if(this.isLoading()){
9721 this.destroyTrans(this.trans);
9726 destroyTrans : function(trans, isLoaded){
9727 this.head.removeChild(document.getElementById(trans.scriptId));
9728 clearTimeout(trans.timeoutId);
9730 window[trans.cb] = undefined;
9732 delete window[trans.cb];
9735 // if hasn't been loaded, wait for load to remove it to prevent script error
9736 window[trans.cb] = function(){
9737 window[trans.cb] = undefined;
9739 delete window[trans.cb];
9746 handleResponse : function(o, trans){
9748 this.destroyTrans(trans, true);
9751 result = trans.reader.readRecords(o);
9753 this.fireEvent("loadexception", this, o, trans.arg, e);
9754 trans.callback.call(trans.scope||window, null, trans.arg, false);
9757 this.fireEvent("load", this, o, trans.arg);
9758 trans.callback.call(trans.scope||window, result, trans.arg, true);
9762 handleFailure : function(trans){
9764 this.destroyTrans(trans, false);
9765 this.fireEvent("loadexception", this, null, trans.arg);
9766 trans.callback.call(trans.scope||window, null, trans.arg, false);
9770 * Ext JS Library 1.1.1
9771 * Copyright(c) 2006-2007, Ext JS, LLC.
9773 * Originally Released Under LGPL - original licence link has changed is not relivant.
9776 * <script type="text/javascript">
9780 * @class Roo.data.JsonReader
9781 * @extends Roo.data.DataReader
9782 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9783 * based on mappings in a provided Roo.data.Record constructor.
9785 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9786 * in the reply previously.
9791 var RecordDef = Roo.data.Record.create([
9792 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9793 {name: 'occupation'} // This field will use "occupation" as the mapping.
9795 var myReader = new Roo.data.JsonReader({
9796 totalProperty: "results", // The property which contains the total dataset size (optional)
9797 root: "rows", // The property which contains an Array of row objects
9798 id: "id" // The property within each row object that provides an ID for the record (optional)
9802 * This would consume a JSON file like this:
9804 { 'results': 2, 'rows': [
9805 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9806 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9809 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9810 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9811 * paged from the remote server.
9812 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9813 * @cfg {String} root name of the property which contains the Array of row objects.
9814 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9816 * Create a new JsonReader
9817 * @param {Object} meta Metadata configuration options
9818 * @param {Object} recordType Either an Array of field definition objects,
9819 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9821 Roo.data.JsonReader = function(meta, recordType){
9824 // set some defaults:
9826 totalProperty: 'total',
9827 successProperty : 'success',
9832 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9834 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9837 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9838 * Used by Store query builder to append _requestMeta to params.
9841 metaFromRemote : false,
9843 * This method is only used by a DataProxy which has retrieved data from a remote server.
9844 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9845 * @return {Object} data A data block which is used by an Roo.data.Store object as
9846 * a cache of Roo.data.Records.
9848 read : function(response){
9849 var json = response.responseText;
9851 var o = /* eval:var:o */ eval("("+json+")");
9853 throw {message: "JsonReader.read: Json object not found"};
9859 this.metaFromRemote = true;
9860 this.meta = o.metaData;
9861 this.recordType = Roo.data.Record.create(o.metaData.fields);
9862 this.onMetaChange(this.meta, this.recordType, o);
9864 return this.readRecords(o);
9867 // private function a store will implement
9868 onMetaChange : function(meta, recordType, o){
9875 simpleAccess: function(obj, subsc) {
9882 getJsonAccessor: function(){
9884 return function(expr) {
9886 return(re.test(expr))
9887 ? new Function("obj", "return obj." + expr)
9897 * Create a data block containing Roo.data.Records from an XML document.
9898 * @param {Object} o An object which contains an Array of row objects in the property specified
9899 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9900 * which contains the total size of the dataset.
9901 * @return {Object} data A data block which is used by an Roo.data.Store object as
9902 * a cache of Roo.data.Records.
9904 readRecords : function(o){
9906 * After any data loads, the raw JSON data is available for further custom processing.
9910 var s = this.meta, Record = this.recordType,
9911 f = Record.prototype.fields, fi = f.items, fl = f.length;
9913 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9915 if(s.totalProperty) {
9916 this.getTotal = this.getJsonAccessor(s.totalProperty);
9918 if(s.successProperty) {
9919 this.getSuccess = this.getJsonAccessor(s.successProperty);
9921 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9923 var g = this.getJsonAccessor(s.id);
9924 this.getId = function(rec) {
9926 return (r === undefined || r === "") ? null : r;
9929 this.getId = function(){return null;};
9932 for(var jj = 0; jj < fl; jj++){
9934 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9935 this.ef[jj] = this.getJsonAccessor(map);
9939 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9940 if(s.totalProperty){
9941 var vt = parseInt(this.getTotal(o), 10);
9946 if(s.successProperty){
9947 var vs = this.getSuccess(o);
9948 if(vs === false || vs === 'false'){
9953 for(var i = 0; i < c; i++){
9956 var id = this.getId(n);
9957 for(var j = 0; j < fl; j++){
9959 var v = this.ef[j](n);
9961 Roo.log('missing convert for ' + f.name);
9965 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9967 var record = new Record(values, id);
9969 records[i] = record;
9975 totalRecords : totalRecords
9980 * Ext JS Library 1.1.1
9981 * Copyright(c) 2006-2007, Ext JS, LLC.
9983 * Originally Released Under LGPL - original licence link has changed is not relivant.
9986 * <script type="text/javascript">
9990 * @class Roo.data.ArrayReader
9991 * @extends Roo.data.DataReader
9992 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9993 * Each element of that Array represents a row of data fields. The
9994 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9995 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9999 var RecordDef = Roo.data.Record.create([
10000 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10001 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10003 var myReader = new Roo.data.ArrayReader({
10004 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10008 * This would consume an Array like this:
10010 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10012 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10014 * Create a new JsonReader
10015 * @param {Object} meta Metadata configuration options.
10016 * @param {Object} recordType Either an Array of field definition objects
10017 * as specified to {@link Roo.data.Record#create},
10018 * or an {@link Roo.data.Record} object
10019 * created using {@link Roo.data.Record#create}.
10021 Roo.data.ArrayReader = function(meta, recordType){
10022 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10025 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10027 * Create a data block containing Roo.data.Records from an XML document.
10028 * @param {Object} o An Array of row objects which represents the dataset.
10029 * @return {Object} data A data block which is used by an Roo.data.Store object as
10030 * a cache of Roo.data.Records.
10032 readRecords : function(o){
10033 var sid = this.meta ? this.meta.id : null;
10034 var recordType = this.recordType, fields = recordType.prototype.fields;
10037 for(var i = 0; i < root.length; i++){
10040 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10041 for(var j = 0, jlen = fields.length; j < jlen; j++){
10042 var f = fields.items[j];
10043 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10044 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10046 values[f.name] = v;
10048 var record = new recordType(values, id);
10050 records[records.length] = record;
10054 totalRecords : records.length
10063 * @class Roo.bootstrap.ComboBox
10064 * @extends Roo.bootstrap.TriggerField
10065 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10066 * @cfg {Boolean} append (true|false) default false
10067 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10068 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10069 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10071 * Create a new ComboBox.
10072 * @param {Object} config Configuration options
10074 Roo.bootstrap.ComboBox = function(config){
10075 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10079 * Fires when the dropdown list is expanded
10080 * @param {Roo.bootstrap.ComboBox} combo This combo box
10085 * Fires when the dropdown list is collapsed
10086 * @param {Roo.bootstrap.ComboBox} combo This combo box
10090 * @event beforeselect
10091 * Fires before a list item is selected. Return false to cancel the selection.
10092 * @param {Roo.bootstrap.ComboBox} combo This combo box
10093 * @param {Roo.data.Record} record The data record returned from the underlying store
10094 * @param {Number} index The index of the selected item in the dropdown list
10096 'beforeselect' : true,
10099 * Fires when a list item is selected
10100 * @param {Roo.bootstrap.ComboBox} combo This combo box
10101 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10102 * @param {Number} index The index of the selected item in the dropdown list
10106 * @event beforequery
10107 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10108 * The event object passed has these properties:
10109 * @param {Roo.bootstrap.ComboBox} combo This combo box
10110 * @param {String} query The query
10111 * @param {Boolean} forceAll true to force "all" query
10112 * @param {Boolean} cancel true to cancel the query
10113 * @param {Object} e The query event object
10115 'beforequery': true,
10118 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10119 * @param {Roo.bootstrap.ComboBox} combo This combo box
10124 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10125 * @param {Roo.bootstrap.ComboBox} combo This combo box
10126 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10131 * Fires when the remove value from the combobox array
10132 * @param {Roo.bootstrap.ComboBox} combo This combo box
10139 this.tickItems = [];
10141 this.selectedIndex = -1;
10142 if(this.mode == 'local'){
10143 if(config.queryDelay === undefined){
10144 this.queryDelay = 10;
10146 if(config.minChars === undefined){
10152 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10155 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10156 * rendering into an Roo.Editor, defaults to false)
10159 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10160 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10163 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10166 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10167 * the dropdown list (defaults to undefined, with no header element)
10171 * @cfg {String/Roo.Template} tpl The template to use to render the output
10175 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10177 listWidth: undefined,
10179 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10180 * mode = 'remote' or 'text' if mode = 'local')
10182 displayField: undefined,
10184 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10185 * mode = 'remote' or 'value' if mode = 'local').
10186 * Note: use of a valueField requires the user make a selection
10187 * in order for a value to be mapped.
10189 valueField: undefined,
10193 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10194 * field's data value (defaults to the underlying DOM element's name)
10196 hiddenName: undefined,
10198 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10202 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10204 selectedClass: 'active',
10207 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10211 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10212 * anchor positions (defaults to 'tl-bl')
10214 listAlign: 'tl-bl?',
10216 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10220 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10221 * query specified by the allQuery config option (defaults to 'query')
10223 triggerAction: 'query',
10225 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10226 * (defaults to 4, does not apply if editable = false)
10230 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10231 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10235 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10236 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10240 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10241 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10245 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10246 * when editable = true (defaults to false)
10248 selectOnFocus:false,
10250 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10252 queryParam: 'query',
10254 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10255 * when mode = 'remote' (defaults to 'Loading...')
10257 loadingText: 'Loading...',
10259 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10263 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10267 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10268 * traditional select (defaults to true)
10272 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10276 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10280 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10281 * listWidth has a higher value)
10285 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10286 * allow the user to set arbitrary text into the field (defaults to false)
10288 forceSelection:false,
10290 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10291 * if typeAhead = true (defaults to 250)
10293 typeAheadDelay : 250,
10295 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10296 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10298 valueNotFoundText : undefined,
10300 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10302 blockFocus : false,
10305 * @cfg {Boolean} disableClear Disable showing of clear button.
10307 disableClear : false,
10309 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10311 alwaysQuery : false,
10314 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10328 btnPosition : 'right',
10329 editNotList : false,
10330 // element that contains real text value.. (when hidden is used..)
10332 getAutoCreate : function()
10339 if(!this.tickable){
10340 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10345 * ComboBox with tickable selections
10348 var align = this.labelAlign || this.parentLabelAlign();
10351 cls : 'form-group roo-combobox-tickable' //input-group
10357 cls : 'tickable-buttons',
10362 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10369 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10376 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10383 Roo.each(buttons.cn, function(c){
10385 c.cls += ' btn-' + _this.size;
10388 if (_this.disabled) {
10399 cls: 'form-hidden-field'
10403 cls: 'select2-choices',
10407 cls: 'select2-search-field',
10419 cls: 'select2-container input-group select2-container-multi',
10424 cls: 'typeahead typeahead-long dropdown-menu',
10425 style: 'display:none; max-height:' + this.maxHeight + 'px;'
10430 if (align ==='left' && this.fieldLabel.length) {
10432 Roo.log("left and has label");
10438 cls : 'control-label col-sm-' + this.labelWidth,
10439 html : this.fieldLabel
10443 cls : "col-sm-" + (12 - this.labelWidth),
10450 } else if ( this.fieldLabel.length) {
10456 //cls : 'input-group-addon',
10457 html : this.fieldLabel
10467 Roo.log(" no label && no align");
10474 ['xs','sm','md','lg'].map(function(size){
10475 if (settings[size]) {
10476 cfg.cls += ' col-' + size + '-' + settings[size];
10485 initEvents: function()
10489 throw "can not find store for combo";
10491 this.store = Roo.factory(this.store, Roo.data);
10494 this.initTickableEvnets();
10498 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10501 if(this.hiddenName){
10503 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10505 this.hiddenField.dom.value =
10506 this.hiddenValue !== undefined ? this.hiddenValue :
10507 this.value !== undefined ? this.value : '';
10509 // prevent input submission
10510 this.el.dom.removeAttribute('name');
10511 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10516 // this.el.dom.setAttribute('autocomplete', 'off');
10519 var cls = 'x-combo-list';
10520 this.list = this.el.select('ul.dropdown-menu',true).first();
10522 //this.list = new Roo.Layer({
10523 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10529 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10530 _this.list.setWidth(lw);
10533 this.list.on('mouseover', this.onViewOver, this);
10534 this.list.on('mousemove', this.onViewMove, this);
10536 this.list.on('scroll', this.onViewScroll, this);
10539 this.list.swallowEvent('mousewheel');
10540 this.assetHeight = 0;
10543 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10544 this.assetHeight += this.header.getHeight();
10547 this.innerList = this.list.createChild({cls:cls+'-inner'});
10548 this.innerList.on('mouseover', this.onViewOver, this);
10549 this.innerList.on('mousemove', this.onViewMove, this);
10550 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10552 if(this.allowBlank && !this.pageSize && !this.disableClear){
10553 this.footer = this.list.createChild({cls:cls+'-ft'});
10554 this.pageTb = new Roo.Toolbar(this.footer);
10558 this.footer = this.list.createChild({cls:cls+'-ft'});
10559 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10560 {pageSize: this.pageSize});
10564 if (this.pageTb && this.allowBlank && !this.disableClear) {
10566 this.pageTb.add(new Roo.Toolbar.Fill(), {
10567 cls: 'x-btn-icon x-btn-clear',
10569 handler: function()
10572 _this.clearValue();
10573 _this.onSelect(false, -1);
10578 this.assetHeight += this.footer.getHeight();
10583 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10586 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10587 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10589 //this.view.wrapEl.setDisplayed(false);
10590 this.view.on('click', this.onViewClick, this);
10594 this.store.on('beforeload', this.onBeforeLoad, this);
10595 this.store.on('load', this.onLoad, this);
10596 this.store.on('loadexception', this.onLoadException, this);
10598 if(this.resizable){
10599 this.resizer = new Roo.Resizable(this.list, {
10600 pinned:true, handles:'se'
10602 this.resizer.on('resize', function(r, w, h){
10603 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10604 this.listWidth = w;
10605 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10606 this.restrictHeight();
10608 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10611 if(!this.editable){
10612 this.editable = true;
10613 this.setEditable(false);
10618 if (typeof(this.events.add.listeners) != 'undefined') {
10620 this.addicon = this.wrap.createChild(
10621 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10623 this.addicon.on('click', function(e) {
10624 this.fireEvent('add', this);
10627 if (typeof(this.events.edit.listeners) != 'undefined') {
10629 this.editicon = this.wrap.createChild(
10630 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10631 if (this.addicon) {
10632 this.editicon.setStyle('margin-left', '40px');
10634 this.editicon.on('click', function(e) {
10636 // we fire even if inothing is selected..
10637 this.fireEvent('edit', this, this.lastData );
10643 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10644 "up" : function(e){
10645 this.inKeyMode = true;
10649 "down" : function(e){
10650 if(!this.isExpanded()){
10651 this.onTriggerClick();
10653 this.inKeyMode = true;
10658 "enter" : function(e){
10659 // this.onViewClick();
10663 if(this.fireEvent("specialkey", this, e)){
10664 this.onViewClick(false);
10670 "esc" : function(e){
10674 "tab" : function(e){
10677 if(this.fireEvent("specialkey", this, e)){
10678 this.onViewClick(false);
10686 doRelay : function(foo, bar, hname){
10687 if(hname == 'down' || this.scope.isExpanded()){
10688 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10697 this.queryDelay = Math.max(this.queryDelay || 10,
10698 this.mode == 'local' ? 10 : 250);
10701 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10703 if(this.typeAhead){
10704 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10706 if(this.editable !== false){
10707 this.inputEl().on("keyup", this.onKeyUp, this);
10709 if(this.forceSelection){
10710 this.inputEl().on('blur', this.doForce, this);
10714 this.choices = this.el.select('ul.select2-choices', true).first();
10715 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10719 initTickableEvnets: function()
10721 if(this.hiddenName){
10723 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10725 this.hiddenField.dom.value =
10726 this.hiddenValue !== undefined ? this.hiddenValue :
10727 this.value !== undefined ? this.value : '';
10729 // prevent input submission
10730 this.el.dom.removeAttribute('name');
10731 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10736 this.list = this.el.select('ul.dropdown-menu',true).first();
10738 this.choices = this.el.select('ul.select2-choices', true).first();
10739 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10740 if(this.editNotList){
10741 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10744 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10745 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10747 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10748 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10750 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10751 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10753 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10754 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10755 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10758 this.cancelBtn.hide();
10763 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10764 _this.list.setWidth(lw);
10767 this.list.on('mouseover', this.onViewOver, this);
10768 this.list.on('mousemove', this.onViewMove, this);
10770 this.list.on('scroll', this.onViewScroll, this);
10773 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>';
10776 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10777 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10780 //this.view.wrapEl.setDisplayed(false);
10781 this.view.on('click', this.onViewClick, this);
10785 this.store.on('beforeload', this.onBeforeLoad, this);
10786 this.store.on('load', this.onLoad, this);
10787 this.store.on('loadexception', this.onLoadException, this);
10789 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10790 // "up" : function(e){
10791 // this.inKeyMode = true;
10792 // this.selectPrev();
10795 // "down" : function(e){
10796 // if(!this.isExpanded()){
10797 // this.onTriggerClick();
10799 // this.inKeyMode = true;
10800 // this.selectNext();
10804 // "enter" : function(e){
10805 //// this.onViewClick();
10807 // this.collapse();
10809 // if(this.fireEvent("specialkey", this, e)){
10810 // this.onViewClick(false);
10816 // "esc" : function(e){
10817 // this.collapse();
10820 // "tab" : function(e){
10821 // this.collapse();
10823 // if(this.fireEvent("specialkey", this, e)){
10824 // this.onViewClick(false);
10832 // doRelay : function(foo, bar, hname){
10833 // if(hname == 'down' || this.scope.isExpanded()){
10834 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10839 // forceKeyDown: true
10843 this.queryDelay = Math.max(this.queryDelay || 10,
10844 this.mode == 'local' ? 10 : 250);
10847 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10849 if(this.typeAhead){
10850 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10854 onDestroy : function(){
10856 this.view.setStore(null);
10857 this.view.el.removeAllListeners();
10858 this.view.el.remove();
10859 this.view.purgeListeners();
10862 this.list.dom.innerHTML = '';
10866 this.store.un('beforeload', this.onBeforeLoad, this);
10867 this.store.un('load', this.onLoad, this);
10868 this.store.un('loadexception', this.onLoadException, this);
10870 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10874 fireKey : function(e){
10875 if(e.isNavKeyPress() && !this.list.isVisible()){
10876 this.fireEvent("specialkey", this, e);
10881 onResize: function(w, h){
10882 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10884 // if(typeof w != 'number'){
10885 // // we do not handle it!?!?
10888 // var tw = this.trigger.getWidth();
10889 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10890 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10892 // this.inputEl().setWidth( this.adjustWidth('input', x));
10894 // //this.trigger.setStyle('left', x+'px');
10896 // if(this.list && this.listWidth === undefined){
10897 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10898 // this.list.setWidth(lw);
10899 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10907 * Allow or prevent the user from directly editing the field text. If false is passed,
10908 * the user will only be able to select from the items defined in the dropdown list. This method
10909 * is the runtime equivalent of setting the 'editable' config option at config time.
10910 * @param {Boolean} value True to allow the user to directly edit the field text
10912 setEditable : function(value){
10913 if(value == this.editable){
10916 this.editable = value;
10918 this.inputEl().dom.setAttribute('readOnly', true);
10919 this.inputEl().on('mousedown', this.onTriggerClick, this);
10920 this.inputEl().addClass('x-combo-noedit');
10922 this.inputEl().dom.setAttribute('readOnly', false);
10923 this.inputEl().un('mousedown', this.onTriggerClick, this);
10924 this.inputEl().removeClass('x-combo-noedit');
10930 onBeforeLoad : function(combo,opts){
10931 if(!this.hasFocus){
10935 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10937 this.restrictHeight();
10938 this.selectedIndex = -1;
10942 onLoad : function(){
10944 this.hasQuery = false;
10946 if(!this.hasFocus){
10950 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10951 this.loading.hide();
10954 if(this.store.getCount() > 0){
10956 this.restrictHeight();
10957 if(this.lastQuery == this.allQuery){
10958 if(this.editable && !this.tickable){
10959 this.inputEl().dom.select();
10961 if(!this.selectByValue(this.value, true) && this.autoFocus){
10962 this.select(0, true);
10965 if(this.autoFocus){
10968 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10969 this.taTask.delay(this.typeAheadDelay);
10973 this.onEmptyResults();
10979 onLoadException : function()
10981 this.hasQuery = false;
10983 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10984 this.loading.hide();
10988 Roo.log(this.store.reader.jsonData);
10989 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10991 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10997 onTypeAhead : function(){
10998 if(this.store.getCount() > 0){
10999 var r = this.store.getAt(0);
11000 var newValue = r.data[this.displayField];
11001 var len = newValue.length;
11002 var selStart = this.getRawValue().length;
11004 if(selStart != len){
11005 this.setRawValue(newValue);
11006 this.selectText(selStart, newValue.length);
11012 onSelect : function(record, index){
11014 if(this.fireEvent('beforeselect', this, record, index) !== false){
11016 this.setFromData(index > -1 ? record.data : false);
11019 this.fireEvent('select', this, record, index);
11024 * Returns the currently selected field value or empty string if no value is set.
11025 * @return {String} value The selected value
11027 getValue : function(){
11030 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11033 if(this.valueField){
11034 return typeof this.value != 'undefined' ? this.value : '';
11036 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11041 * Clears any text/value currently set in the field
11043 clearValue : function(){
11044 if(this.hiddenField){
11045 this.hiddenField.dom.value = '';
11048 this.setRawValue('');
11049 this.lastSelectionText = '';
11054 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11055 * will be displayed in the field. If the value does not match the data value of an existing item,
11056 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11057 * Otherwise the field will be blank (although the value will still be set).
11058 * @param {String} value The value to match
11060 setValue : function(v){
11067 if(this.valueField){
11068 var r = this.findRecord(this.valueField, v);
11070 text = r.data[this.displayField];
11071 }else if(this.valueNotFoundText !== undefined){
11072 text = this.valueNotFoundText;
11075 this.lastSelectionText = text;
11076 if(this.hiddenField){
11077 this.hiddenField.dom.value = v;
11079 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11083 * @property {Object} the last set data for the element
11088 * Sets the value of the field based on a object which is related to the record format for the store.
11089 * @param {Object} value the value to set as. or false on reset?
11091 setFromData : function(o){
11098 var dv = ''; // display value
11099 var vv = ''; // value value..
11101 if (this.displayField) {
11102 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11104 // this is an error condition!!!
11105 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11108 if(this.valueField){
11109 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11112 if(this.hiddenField){
11113 this.hiddenField.dom.value = vv;
11115 this.lastSelectionText = dv;
11116 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11120 // no hidden field.. - we store the value in 'value', but still display
11121 // display field!!!!
11122 this.lastSelectionText = dv;
11123 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11129 reset : function(){
11130 // overridden so that last data is reset..
11131 this.setValue(this.originalValue);
11132 this.clearInvalid();
11133 this.lastData = false;
11135 this.view.clearSelections();
11139 findRecord : function(prop, value){
11141 if(this.store.getCount() > 0){
11142 this.store.each(function(r){
11143 if(r.data[prop] == value){
11153 getName: function()
11155 // returns hidden if it's set..
11156 if (!this.rendered) {return ''};
11157 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11161 onViewMove : function(e, t){
11162 this.inKeyMode = false;
11166 onViewOver : function(e, t){
11167 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11170 var item = this.view.findItemFromChild(t);
11173 var index = this.view.indexOf(item);
11174 this.select(index, false);
11179 onViewClick : function(view, doFocus, el, e)
11181 var index = this.view.getSelectedIndexes()[0];
11183 var r = this.store.getAt(index);
11187 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11194 Roo.each(this.tickItems, function(v,k){
11196 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11197 _this.tickItems.splice(k, 1);
11207 this.tickItems.push(r.data);
11212 this.onSelect(r, index);
11214 if(doFocus !== false && !this.blockFocus){
11215 this.inputEl().focus();
11220 restrictHeight : function(){
11221 //this.innerList.dom.style.height = '';
11222 //var inner = this.innerList.dom;
11223 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11224 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11225 //this.list.beginUpdate();
11226 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11227 this.list.alignTo(this.inputEl(), this.listAlign);
11228 //this.list.endUpdate();
11232 onEmptyResults : function(){
11237 * Returns true if the dropdown list is expanded, else false.
11239 isExpanded : function(){
11240 return this.list.isVisible();
11244 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11245 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11246 * @param {String} value The data value of the item to select
11247 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11248 * selected item if it is not currently in view (defaults to true)
11249 * @return {Boolean} True if the value matched an item in the list, else false
11251 selectByValue : function(v, scrollIntoView){
11252 if(v !== undefined && v !== null){
11253 var r = this.findRecord(this.valueField || this.displayField, v);
11255 this.select(this.store.indexOf(r), scrollIntoView);
11263 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11264 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11265 * @param {Number} index The zero-based index of the list item to select
11266 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11267 * selected item if it is not currently in view (defaults to true)
11269 select : function(index, scrollIntoView){
11270 this.selectedIndex = index;
11271 this.view.select(index);
11272 if(scrollIntoView !== false){
11273 var el = this.view.getNode(index);
11275 //this.innerList.scrollChildIntoView(el, false);
11282 selectNext : function(){
11283 var ct = this.store.getCount();
11285 if(this.selectedIndex == -1){
11287 }else if(this.selectedIndex < ct-1){
11288 this.select(this.selectedIndex+1);
11294 selectPrev : function(){
11295 var ct = this.store.getCount();
11297 if(this.selectedIndex == -1){
11299 }else if(this.selectedIndex != 0){
11300 this.select(this.selectedIndex-1);
11306 onKeyUp : function(e){
11307 if(this.editable !== false && !e.isSpecialKey()){
11308 this.lastKey = e.getKey();
11309 this.dqTask.delay(this.queryDelay);
11314 validateBlur : function(){
11315 return !this.list || !this.list.isVisible();
11319 initQuery : function(){
11320 this.doQuery(this.getRawValue());
11324 doForce : function(){
11325 if(this.inputEl().dom.value.length > 0){
11326 this.inputEl().dom.value =
11327 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11333 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11334 * query allowing the query action to be canceled if needed.
11335 * @param {String} query The SQL query to execute
11336 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11337 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11338 * saved in the current store (defaults to false)
11340 doQuery : function(q, forceAll){
11342 if(q === undefined || q === null){
11347 forceAll: forceAll,
11351 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11356 forceAll = qe.forceAll;
11357 if(forceAll === true || (q.length >= this.minChars)){
11359 this.hasQuery = true;
11361 if(this.lastQuery != q || this.alwaysQuery){
11362 this.lastQuery = q;
11363 if(this.mode == 'local'){
11364 this.selectedIndex = -1;
11366 this.store.clearFilter();
11368 this.store.filter(this.displayField, q);
11372 this.store.baseParams[this.queryParam] = q;
11374 var options = {params : this.getParams(q)};
11377 options.add = true;
11378 options.params.start = this.page * this.pageSize;
11381 this.store.load(options);
11383 * this code will make the page width larger, at the beginning, the list not align correctly,
11384 * we should expand the list on onLoad
11385 * so command out it
11390 this.selectedIndex = -1;
11395 this.loadNext = false;
11399 getParams : function(q){
11401 //p[this.queryParam] = q;
11405 p.limit = this.pageSize;
11411 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11413 collapse : function(){
11414 if(!this.isExpanded()){
11418 this.hasFocus = false;
11424 this.cancelBtn.hide();
11425 this.trigger.show();
11428 Roo.get(document).un('mousedown', this.collapseIf, this);
11429 Roo.get(document).un('mousewheel', this.collapseIf, this);
11430 if (!this.editable) {
11431 Roo.get(document).un('keydown', this.listKeyPress, this);
11433 this.fireEvent('collapse', this);
11437 collapseIf : function(e){
11438 var in_combo = e.within(this.el);
11439 var in_list = e.within(this.list);
11441 if (in_combo || in_list) {
11442 //e.stopPropagation();
11447 this.onTickableFooterButtonClick(e, false, false);
11455 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11457 expand : function(){
11459 if(this.isExpanded() || !this.hasFocus){
11463 this.list.alignTo(this.inputEl(), this.listAlign);
11468 this.tickItems = Roo.apply([], this.item);
11471 this.cancelBtn.show();
11472 this.trigger.hide();
11476 Roo.get(document).on('mousedown', this.collapseIf, this);
11477 Roo.get(document).on('mousewheel', this.collapseIf, this);
11478 if (!this.editable) {
11479 Roo.get(document).on('keydown', this.listKeyPress, this);
11482 this.fireEvent('expand', this);
11486 // Implements the default empty TriggerField.onTriggerClick function
11487 onTriggerClick : function(e)
11489 Roo.log('trigger click');
11496 this.loadNext = false;
11498 if(this.isExpanded()){
11500 if (!this.blockFocus) {
11501 this.inputEl().focus();
11505 this.hasFocus = true;
11506 if(this.triggerAction == 'all') {
11507 this.doQuery(this.allQuery, true);
11509 this.doQuery(this.getRawValue());
11511 if (!this.blockFocus) {
11512 this.inputEl().focus();
11517 onTickableTriggerClick : function(e)
11524 this.loadNext = false;
11525 this.hasFocus = true;
11527 if(this.triggerAction == 'all') {
11528 this.doQuery(this.allQuery, true);
11530 this.doQuery(this.getRawValue());
11534 onSearchFieldClick : function(e)
11536 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
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 listKeyPress : function(e)
11553 //Roo.log('listkeypress');
11554 // scroll to first matching element based on key pres..
11555 if (e.isSpecialKey()) {
11558 var k = String.fromCharCode(e.getKey()).toUpperCase();
11561 var csel = this.view.getSelectedNodes();
11562 var cselitem = false;
11564 var ix = this.view.indexOf(csel[0]);
11565 cselitem = this.store.getAt(ix);
11566 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11572 this.store.each(function(v) {
11574 // start at existing selection.
11575 if (cselitem.id == v.id) {
11581 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11582 match = this.store.indexOf(v);
11588 if (match === false) {
11589 return true; // no more action?
11592 this.view.select(match);
11593 var sn = Roo.get(this.view.getSelectedNodes()[0])
11594 //sn.scrollIntoView(sn.dom.parentNode, false);
11597 onViewScroll : function(e, t){
11599 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11603 this.hasQuery = true;
11605 this.loading = this.list.select('.loading', true).first();
11607 if(this.loading === null){
11608 this.list.createChild({
11610 cls: 'loading select2-more-results select2-active',
11611 html: 'Loading more results...'
11614 this.loading = this.list.select('.loading', true).first();
11616 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11618 this.loading.hide();
11621 this.loading.show();
11626 this.loadNext = true;
11628 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11633 addItem : function(o)
11635 var dv = ''; // display value
11637 if (this.displayField) {
11638 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11640 // this is an error condition!!!
11641 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11648 var choice = this.choices.createChild({
11650 cls: 'select2-search-choice',
11659 cls: 'select2-search-choice-close',
11664 }, this.searchField);
11666 var close = choice.select('a.select2-search-choice-close', true).first()
11668 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11676 this.inputEl().dom.value = '';
11680 onRemoveItem : function(e, _self, o)
11682 e.preventDefault();
11683 var index = this.item.indexOf(o.data) * 1;
11686 Roo.log('not this item?!');
11690 this.item.splice(index, 1);
11695 this.fireEvent('remove', this, e);
11699 syncValue : function()
11701 if(!this.item.length){
11708 Roo.each(this.item, function(i){
11709 if(_this.valueField){
11710 value.push(i[_this.valueField]);
11717 this.value = value.join(',');
11719 if(this.hiddenField){
11720 this.hiddenField.dom.value = this.value;
11724 clearItem : function()
11726 if(!this.multiple){
11732 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11739 inputEl: function ()
11742 return this.searchField;
11744 return this.el.select('input.form-control',true).first();
11748 onTickableFooterButtonClick : function(e, btn, el)
11750 e.preventDefault();
11752 if(btn && btn.name == 'cancel'){
11753 this.tickItems = Roo.apply([], this.item);
11762 Roo.each(this.tickItems, function(o){
11773 * @cfg {Boolean} grow
11777 * @cfg {Number} growMin
11781 * @cfg {Number} growMax
11791 * Ext JS Library 1.1.1
11792 * Copyright(c) 2006-2007, Ext JS, LLC.
11794 * Originally Released Under LGPL - original licence link has changed is not relivant.
11797 * <script type="text/javascript">
11802 * @extends Roo.util.Observable
11803 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11804 * This class also supports single and multi selection modes. <br>
11805 * Create a data model bound view:
11807 var store = new Roo.data.Store(...);
11809 var view = new Roo.View({
11811 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11813 singleSelect: true,
11814 selectedClass: "ydataview-selected",
11818 // listen for node click?
11819 view.on("click", function(vw, index, node, e){
11820 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11824 dataModel.load("foobar.xml");
11826 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11828 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11829 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11831 * Note: old style constructor is still suported (container, template, config)
11834 * Create a new View
11835 * @param {Object} config The config object
11838 Roo.View = function(config, depreciated_tpl, depreciated_config){
11840 this.parent = false;
11842 if (typeof(depreciated_tpl) == 'undefined') {
11843 // new way.. - universal constructor.
11844 Roo.apply(this, config);
11845 this.el = Roo.get(this.el);
11848 this.el = Roo.get(config);
11849 this.tpl = depreciated_tpl;
11850 Roo.apply(this, depreciated_config);
11852 this.wrapEl = this.el.wrap().wrap();
11853 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11856 if(typeof(this.tpl) == "string"){
11857 this.tpl = new Roo.Template(this.tpl);
11859 // support xtype ctors..
11860 this.tpl = new Roo.factory(this.tpl, Roo);
11864 this.tpl.compile();
11869 * @event beforeclick
11870 * Fires before a click is processed. Returns false to cancel the default action.
11871 * @param {Roo.View} this
11872 * @param {Number} index The index of the target node
11873 * @param {HTMLElement} node The target node
11874 * @param {Roo.EventObject} e The raw event object
11876 "beforeclick" : true,
11879 * Fires when a template node is clicked.
11880 * @param {Roo.View} this
11881 * @param {Number} index The index of the target node
11882 * @param {HTMLElement} node The target node
11883 * @param {Roo.EventObject} e The raw event object
11888 * Fires when a template node is double clicked.
11889 * @param {Roo.View} this
11890 * @param {Number} index The index of the target node
11891 * @param {HTMLElement} node The target node
11892 * @param {Roo.EventObject} e The raw event object
11896 * @event contextmenu
11897 * Fires when a template node is right clicked.
11898 * @param {Roo.View} this
11899 * @param {Number} index The index of the target node
11900 * @param {HTMLElement} node The target node
11901 * @param {Roo.EventObject} e The raw event object
11903 "contextmenu" : true,
11905 * @event selectionchange
11906 * Fires when the selected nodes change.
11907 * @param {Roo.View} this
11908 * @param {Array} selections Array of the selected nodes
11910 "selectionchange" : true,
11913 * @event beforeselect
11914 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11915 * @param {Roo.View} this
11916 * @param {HTMLElement} node The node to be selected
11917 * @param {Array} selections Array of currently selected nodes
11919 "beforeselect" : true,
11921 * @event preparedata
11922 * Fires on every row to render, to allow you to change the data.
11923 * @param {Roo.View} this
11924 * @param {Object} data to be rendered (change this)
11926 "preparedata" : true
11934 "click": this.onClick,
11935 "dblclick": this.onDblClick,
11936 "contextmenu": this.onContextMenu,
11940 this.selections = [];
11942 this.cmp = new Roo.CompositeElementLite([]);
11944 this.store = Roo.factory(this.store, Roo.data);
11945 this.setStore(this.store, true);
11948 if ( this.footer && this.footer.xtype) {
11950 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11952 this.footer.dataSource = this.store
11953 this.footer.container = fctr;
11954 this.footer = Roo.factory(this.footer, Roo);
11955 fctr.insertFirst(this.el);
11957 // this is a bit insane - as the paging toolbar seems to detach the el..
11958 // dom.parentNode.parentNode.parentNode
11959 // they get detached?
11963 Roo.View.superclass.constructor.call(this);
11968 Roo.extend(Roo.View, Roo.util.Observable, {
11971 * @cfg {Roo.data.Store} store Data store to load data from.
11976 * @cfg {String|Roo.Element} el The container element.
11981 * @cfg {String|Roo.Template} tpl The template used by this View
11985 * @cfg {String} dataName the named area of the template to use as the data area
11986 * Works with domtemplates roo-name="name"
11990 * @cfg {String} selectedClass The css class to add to selected nodes
11992 selectedClass : "x-view-selected",
11994 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11999 * @cfg {String} text to display on mask (default Loading)
12003 * @cfg {Boolean} multiSelect Allow multiple selection
12005 multiSelect : false,
12007 * @cfg {Boolean} singleSelect Allow single selection
12009 singleSelect: false,
12012 * @cfg {Boolean} toggleSelect - selecting
12014 toggleSelect : false,
12017 * @cfg {Boolean} tickable - selecting
12022 * Returns the element this view is bound to.
12023 * @return {Roo.Element}
12025 getEl : function(){
12026 return this.wrapEl;
12032 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12034 refresh : function(){
12035 Roo.log('refresh');
12038 // if we are using something like 'domtemplate', then
12039 // the what gets used is:
12040 // t.applySubtemplate(NAME, data, wrapping data..)
12041 // the outer template then get' applied with
12042 // the store 'extra data'
12043 // and the body get's added to the
12044 // roo-name="data" node?
12045 // <span class='roo-tpl-{name}'></span> ?????
12049 this.clearSelections();
12050 this.el.update("");
12052 var records = this.store.getRange();
12053 if(records.length < 1) {
12055 // is this valid?? = should it render a template??
12057 this.el.update(this.emptyText);
12061 if (this.dataName) {
12062 this.el.update(t.apply(this.store.meta)); //????
12063 el = this.el.child('.roo-tpl-' + this.dataName);
12066 for(var i = 0, len = records.length; i < len; i++){
12067 var data = this.prepareData(records[i].data, i, records[i]);
12068 this.fireEvent("preparedata", this, data, i, records[i]);
12070 var d = Roo.apply({}, data);
12073 Roo.apply(d, {'roo-id' : Roo.id()});
12077 Roo.each(this.parent.item, function(item){
12078 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12081 Roo.apply(d, {'roo-data-checked' : 'checked'});
12085 html[html.length] = Roo.util.Format.trim(
12087 t.applySubtemplate(this.dataName, d, this.store.meta) :
12094 el.update(html.join(""));
12095 this.nodes = el.dom.childNodes;
12096 this.updateIndexes(0);
12101 * Function to override to reformat the data that is sent to
12102 * the template for each node.
12103 * DEPRICATED - use the preparedata event handler.
12104 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12105 * a JSON object for an UpdateManager bound view).
12107 prepareData : function(data, index, record)
12109 this.fireEvent("preparedata", this, data, index, record);
12113 onUpdate : function(ds, record){
12114 Roo.log('on update');
12115 this.clearSelections();
12116 var index = this.store.indexOf(record);
12117 var n = this.nodes[index];
12118 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12119 n.parentNode.removeChild(n);
12120 this.updateIndexes(index, index);
12126 onAdd : function(ds, records, index)
12128 Roo.log(['on Add', ds, records, index] );
12129 this.clearSelections();
12130 if(this.nodes.length == 0){
12134 var n = this.nodes[index];
12135 for(var i = 0, len = records.length; i < len; i++){
12136 var d = this.prepareData(records[i].data, i, records[i]);
12138 this.tpl.insertBefore(n, d);
12141 this.tpl.append(this.el, d);
12144 this.updateIndexes(index);
12147 onRemove : function(ds, record, index){
12148 Roo.log('onRemove');
12149 this.clearSelections();
12150 var el = this.dataName ?
12151 this.el.child('.roo-tpl-' + this.dataName) :
12154 el.dom.removeChild(this.nodes[index]);
12155 this.updateIndexes(index);
12159 * Refresh an individual node.
12160 * @param {Number} index
12162 refreshNode : function(index){
12163 this.onUpdate(this.store, this.store.getAt(index));
12166 updateIndexes : function(startIndex, endIndex){
12167 var ns = this.nodes;
12168 startIndex = startIndex || 0;
12169 endIndex = endIndex || ns.length - 1;
12170 for(var i = startIndex; i <= endIndex; i++){
12171 ns[i].nodeIndex = i;
12176 * Changes the data store this view uses and refresh the view.
12177 * @param {Store} store
12179 setStore : function(store, initial){
12180 if(!initial && this.store){
12181 this.store.un("datachanged", this.refresh);
12182 this.store.un("add", this.onAdd);
12183 this.store.un("remove", this.onRemove);
12184 this.store.un("update", this.onUpdate);
12185 this.store.un("clear", this.refresh);
12186 this.store.un("beforeload", this.onBeforeLoad);
12187 this.store.un("load", this.onLoad);
12188 this.store.un("loadexception", this.onLoad);
12192 store.on("datachanged", this.refresh, this);
12193 store.on("add", this.onAdd, this);
12194 store.on("remove", this.onRemove, this);
12195 store.on("update", this.onUpdate, this);
12196 store.on("clear", this.refresh, this);
12197 store.on("beforeload", this.onBeforeLoad, this);
12198 store.on("load", this.onLoad, this);
12199 store.on("loadexception", this.onLoad, this);
12207 * onbeforeLoad - masks the loading area.
12210 onBeforeLoad : function(store,opts)
12212 Roo.log('onBeforeLoad');
12214 this.el.update("");
12216 this.el.mask(this.mask ? this.mask : "Loading" );
12218 onLoad : function ()
12225 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12226 * @param {HTMLElement} node
12227 * @return {HTMLElement} The template node
12229 findItemFromChild : function(node){
12230 var el = this.dataName ?
12231 this.el.child('.roo-tpl-' + this.dataName,true) :
12234 if(!node || node.parentNode == el){
12237 var p = node.parentNode;
12238 while(p && p != el){
12239 if(p.parentNode == el){
12248 onClick : function(e){
12249 var item = this.findItemFromChild(e.getTarget());
12251 var index = this.indexOf(item);
12252 if(this.onItemClick(item, index, e) !== false){
12253 this.fireEvent("click", this, index, item, e);
12256 this.clearSelections();
12261 onContextMenu : function(e){
12262 var item = this.findItemFromChild(e.getTarget());
12264 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12269 onDblClick : function(e){
12270 var item = this.findItemFromChild(e.getTarget());
12272 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12276 onItemClick : function(item, index, e)
12278 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12281 if (this.toggleSelect) {
12282 var m = this.isSelected(item) ? 'unselect' : 'select';
12285 _t[m](item, true, false);
12288 if(this.multiSelect || this.singleSelect){
12289 if(this.multiSelect && e.shiftKey && this.lastSelection){
12290 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12292 this.select(item, this.multiSelect && e.ctrlKey);
12293 this.lastSelection = item;
12296 if(!this.tickable){
12297 e.preventDefault();
12305 * Get the number of selected nodes.
12308 getSelectionCount : function(){
12309 return this.selections.length;
12313 * Get the currently selected nodes.
12314 * @return {Array} An array of HTMLElements
12316 getSelectedNodes : function(){
12317 return this.selections;
12321 * Get the indexes of the selected nodes.
12324 getSelectedIndexes : function(){
12325 var indexes = [], s = this.selections;
12326 for(var i = 0, len = s.length; i < len; i++){
12327 indexes.push(s[i].nodeIndex);
12333 * Clear all selections
12334 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12336 clearSelections : function(suppressEvent){
12337 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12338 this.cmp.elements = this.selections;
12339 this.cmp.removeClass(this.selectedClass);
12340 this.selections = [];
12341 if(!suppressEvent){
12342 this.fireEvent("selectionchange", this, this.selections);
12348 * Returns true if the passed node is selected
12349 * @param {HTMLElement/Number} node The node or node index
12350 * @return {Boolean}
12352 isSelected : function(node){
12353 var s = this.selections;
12357 node = this.getNode(node);
12358 return s.indexOf(node) !== -1;
12363 * @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
12364 * @param {Boolean} keepExisting (optional) true to keep existing selections
12365 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12367 select : function(nodeInfo, keepExisting, suppressEvent){
12368 if(nodeInfo instanceof Array){
12370 this.clearSelections(true);
12372 for(var i = 0, len = nodeInfo.length; i < len; i++){
12373 this.select(nodeInfo[i], true, true);
12377 var node = this.getNode(nodeInfo);
12378 if(!node || this.isSelected(node)){
12379 return; // already selected.
12382 this.clearSelections(true);
12384 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12385 Roo.fly(node).addClass(this.selectedClass);
12386 this.selections.push(node);
12387 if(!suppressEvent){
12388 this.fireEvent("selectionchange", this, this.selections);
12396 * @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
12397 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12398 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12400 unselect : function(nodeInfo, keepExisting, suppressEvent)
12402 if(nodeInfo instanceof Array){
12403 Roo.each(this.selections, function(s) {
12404 this.unselect(s, nodeInfo);
12408 var node = this.getNode(nodeInfo);
12409 if(!node || !this.isSelected(node)){
12410 Roo.log("not selected");
12411 return; // not selected.
12415 Roo.each(this.selections, function(s) {
12417 Roo.fly(node).removeClass(this.selectedClass);
12424 this.selections= ns;
12425 this.fireEvent("selectionchange", this, this.selections);
12429 * Gets a template node.
12430 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12431 * @return {HTMLElement} The node or null if it wasn't found
12433 getNode : function(nodeInfo){
12434 if(typeof nodeInfo == "string"){
12435 return document.getElementById(nodeInfo);
12436 }else if(typeof nodeInfo == "number"){
12437 return this.nodes[nodeInfo];
12443 * Gets a range template nodes.
12444 * @param {Number} startIndex
12445 * @param {Number} endIndex
12446 * @return {Array} An array of nodes
12448 getNodes : function(start, end){
12449 var ns = this.nodes;
12450 start = start || 0;
12451 end = typeof end == "undefined" ? ns.length - 1 : end;
12454 for(var i = start; i <= end; i++){
12458 for(var i = start; i >= end; i--){
12466 * Finds the index of the passed node
12467 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12468 * @return {Number} The index of the node or -1
12470 indexOf : function(node){
12471 node = this.getNode(node);
12472 if(typeof node.nodeIndex == "number"){
12473 return node.nodeIndex;
12475 var ns = this.nodes;
12476 for(var i = 0, len = ns.length; i < len; i++){
12487 * based on jquery fullcalendar
12491 Roo.bootstrap = Roo.bootstrap || {};
12493 * @class Roo.bootstrap.Calendar
12494 * @extends Roo.bootstrap.Component
12495 * Bootstrap Calendar class
12496 * @cfg {Boolean} loadMask (true|false) default false
12497 * @cfg {Object} header generate the user specific header of the calendar, default false
12500 * Create a new Container
12501 * @param {Object} config The config object
12506 Roo.bootstrap.Calendar = function(config){
12507 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12511 * Fires when a date is selected
12512 * @param {DatePicker} this
12513 * @param {Date} date The selected date
12517 * @event monthchange
12518 * Fires when the displayed month changes
12519 * @param {DatePicker} this
12520 * @param {Date} date The selected month
12522 'monthchange': true,
12524 * @event evententer
12525 * Fires when mouse over an event
12526 * @param {Calendar} this
12527 * @param {event} Event
12529 'evententer': true,
12531 * @event eventleave
12532 * Fires when the mouse leaves an
12533 * @param {Calendar} this
12536 'eventleave': true,
12538 * @event eventclick
12539 * Fires when the mouse click an
12540 * @param {Calendar} this
12549 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12552 * @cfg {Number} startDay
12553 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12561 getAutoCreate : function(){
12564 var fc_button = function(name, corner, style, content ) {
12565 return Roo.apply({},{
12567 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12569 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12572 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12583 style : 'width:100%',
12590 cls : 'fc-header-left',
12592 fc_button('prev', 'left', 'arrow', '‹' ),
12593 fc_button('next', 'right', 'arrow', '›' ),
12594 { tag: 'span', cls: 'fc-header-space' },
12595 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12603 cls : 'fc-header-center',
12607 cls: 'fc-header-title',
12610 html : 'month / year'
12618 cls : 'fc-header-right',
12620 /* fc_button('month', 'left', '', 'month' ),
12621 fc_button('week', '', '', 'week' ),
12622 fc_button('day', 'right', '', 'day' )
12634 header = this.header;
12637 var cal_heads = function() {
12639 // fixme - handle this.
12641 for (var i =0; i < Date.dayNames.length; i++) {
12642 var d = Date.dayNames[i];
12645 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12646 html : d.substring(0,3)
12650 ret[0].cls += ' fc-first';
12651 ret[6].cls += ' fc-last';
12654 var cal_cell = function(n) {
12657 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12662 cls: 'fc-day-number',
12666 cls: 'fc-day-content',
12670 style: 'position: relative;' // height: 17px;
12682 var cal_rows = function() {
12685 for (var r = 0; r < 6; r++) {
12692 for (var i =0; i < Date.dayNames.length; i++) {
12693 var d = Date.dayNames[i];
12694 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12697 row.cn[0].cls+=' fc-first';
12698 row.cn[0].cn[0].style = 'min-height:90px';
12699 row.cn[6].cls+=' fc-last';
12703 ret[0].cls += ' fc-first';
12704 ret[4].cls += ' fc-prev-last';
12705 ret[5].cls += ' fc-last';
12712 cls: 'fc-border-separate',
12713 style : 'width:100%',
12721 cls : 'fc-first fc-last',
12739 cls : 'fc-content',
12740 style : "position: relative;",
12743 cls : 'fc-view fc-view-month fc-grid',
12744 style : 'position: relative',
12745 unselectable : 'on',
12748 cls : 'fc-event-container',
12749 style : 'position:absolute;z-index:8;top:0;left:0;'
12767 initEvents : function()
12770 throw "can not find store for calendar";
12776 style: "text-align:center",
12780 style: "background-color:white;width:50%;margin:250 auto",
12784 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12795 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12797 var size = this.el.select('.fc-content', true).first().getSize();
12798 this.maskEl.setSize(size.width, size.height);
12799 this.maskEl.enableDisplayMode("block");
12800 if(!this.loadMask){
12801 this.maskEl.hide();
12804 this.store = Roo.factory(this.store, Roo.data);
12805 this.store.on('load', this.onLoad, this);
12806 this.store.on('beforeload', this.onBeforeLoad, this);
12810 this.cells = this.el.select('.fc-day',true);
12811 //Roo.log(this.cells);
12812 this.textNodes = this.el.query('.fc-day-number');
12813 this.cells.addClassOnOver('fc-state-hover');
12815 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12816 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12817 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12818 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12820 this.on('monthchange', this.onMonthChange, this);
12822 this.update(new Date().clearTime());
12825 resize : function() {
12826 var sz = this.el.getSize();
12828 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12829 this.el.select('.fc-day-content div',true).setHeight(34);
12834 showPrevMonth : function(e){
12835 this.update(this.activeDate.add("mo", -1));
12837 showToday : function(e){
12838 this.update(new Date().clearTime());
12841 showNextMonth : function(e){
12842 this.update(this.activeDate.add("mo", 1));
12846 showPrevYear : function(){
12847 this.update(this.activeDate.add("y", -1));
12851 showNextYear : function(){
12852 this.update(this.activeDate.add("y", 1));
12857 update : function(date)
12859 var vd = this.activeDate;
12860 this.activeDate = date;
12861 // if(vd && this.el){
12862 // var t = date.getTime();
12863 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12864 // Roo.log('using add remove');
12866 // this.fireEvent('monthchange', this, date);
12868 // this.cells.removeClass("fc-state-highlight");
12869 // this.cells.each(function(c){
12870 // if(c.dateValue == t){
12871 // c.addClass("fc-state-highlight");
12872 // setTimeout(function(){
12873 // try{c.dom.firstChild.focus();}catch(e){}
12883 var days = date.getDaysInMonth();
12885 var firstOfMonth = date.getFirstDateOfMonth();
12886 var startingPos = firstOfMonth.getDay()-this.startDay;
12888 if(startingPos < this.startDay){
12892 var pm = date.add(Date.MONTH, -1);
12893 var prevStart = pm.getDaysInMonth()-startingPos;
12895 this.cells = this.el.select('.fc-day',true);
12896 this.textNodes = this.el.query('.fc-day-number');
12897 this.cells.addClassOnOver('fc-state-hover');
12899 var cells = this.cells.elements;
12900 var textEls = this.textNodes;
12902 Roo.each(cells, function(cell){
12903 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12906 days += startingPos;
12908 // convert everything to numbers so it's fast
12909 var day = 86400000;
12910 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12913 //Roo.log(prevStart);
12915 var today = new Date().clearTime().getTime();
12916 var sel = date.clearTime().getTime();
12917 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12918 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12919 var ddMatch = this.disabledDatesRE;
12920 var ddText = this.disabledDatesText;
12921 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12922 var ddaysText = this.disabledDaysText;
12923 var format = this.format;
12925 var setCellClass = function(cal, cell){
12929 //Roo.log('set Cell Class');
12931 var t = d.getTime();
12935 cell.dateValue = t;
12937 cell.className += " fc-today";
12938 cell.className += " fc-state-highlight";
12939 cell.title = cal.todayText;
12942 // disable highlight in other month..
12943 //cell.className += " fc-state-highlight";
12948 cell.className = " fc-state-disabled";
12949 cell.title = cal.minText;
12953 cell.className = " fc-state-disabled";
12954 cell.title = cal.maxText;
12958 if(ddays.indexOf(d.getDay()) != -1){
12959 cell.title = ddaysText;
12960 cell.className = " fc-state-disabled";
12963 if(ddMatch && format){
12964 var fvalue = d.dateFormat(format);
12965 if(ddMatch.test(fvalue)){
12966 cell.title = ddText.replace("%0", fvalue);
12967 cell.className = " fc-state-disabled";
12971 if (!cell.initialClassName) {
12972 cell.initialClassName = cell.dom.className;
12975 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12980 for(; i < startingPos; i++) {
12981 textEls[i].innerHTML = (++prevStart);
12982 d.setDate(d.getDate()+1);
12984 cells[i].className = "fc-past fc-other-month";
12985 setCellClass(this, cells[i]);
12990 for(; i < days; i++){
12991 intDay = i - startingPos + 1;
12992 textEls[i].innerHTML = (intDay);
12993 d.setDate(d.getDate()+1);
12995 cells[i].className = ''; // "x-date-active";
12996 setCellClass(this, cells[i]);
13000 for(; i < 42; i++) {
13001 textEls[i].innerHTML = (++extraDays);
13002 d.setDate(d.getDate()+1);
13004 cells[i].className = "fc-future fc-other-month";
13005 setCellClass(this, cells[i]);
13008 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13010 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13012 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13013 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13015 if(totalRows != 6){
13016 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13017 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13020 this.fireEvent('monthchange', this, date);
13024 if(!this.internalRender){
13025 var main = this.el.dom.firstChild;
13026 var w = main.offsetWidth;
13027 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13028 Roo.fly(main).setWidth(w);
13029 this.internalRender = true;
13030 // opera does not respect the auto grow header center column
13031 // then, after it gets a width opera refuses to recalculate
13032 // without a second pass
13033 if(Roo.isOpera && !this.secondPass){
13034 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13035 this.secondPass = true;
13036 this.update.defer(10, this, [date]);
13043 findCell : function(dt) {
13044 dt = dt.clearTime().getTime();
13046 this.cells.each(function(c){
13047 //Roo.log("check " +c.dateValue + '?=' + dt);
13048 if(c.dateValue == dt){
13058 findCells : function(ev) {
13059 var s = ev.start.clone().clearTime().getTime();
13061 var e= ev.end.clone().clearTime().getTime();
13064 this.cells.each(function(c){
13065 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13067 if(c.dateValue > e){
13070 if(c.dateValue < s){
13079 // findBestRow: function(cells)
13083 // for (var i =0 ; i < cells.length;i++) {
13084 // ret = Math.max(cells[i].rows || 0,ret);
13091 addItem : function(ev)
13093 // look for vertical location slot in
13094 var cells = this.findCells(ev);
13096 // ev.row = this.findBestRow(cells);
13098 // work out the location.
13102 for(var i =0; i < cells.length; i++) {
13104 cells[i].row = cells[0].row;
13107 cells[i].row = cells[i].row + 1;
13117 if (crow.start.getY() == cells[i].getY()) {
13119 crow.end = cells[i];
13136 cells[0].events.push(ev);
13138 this.calevents.push(ev);
13141 clearEvents: function() {
13143 if(!this.calevents){
13147 Roo.each(this.cells.elements, function(c){
13153 Roo.each(this.calevents, function(e) {
13154 Roo.each(e.els, function(el) {
13155 el.un('mouseenter' ,this.onEventEnter, this);
13156 el.un('mouseleave' ,this.onEventLeave, this);
13161 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13167 renderEvents: function()
13171 this.cells.each(function(c) {
13180 if(c.row != c.events.length){
13181 r = 4 - (4 - (c.row - c.events.length));
13184 c.events = ev.slice(0, r);
13185 c.more = ev.slice(r);
13187 if(c.more.length && c.more.length == 1){
13188 c.events.push(c.more.pop());
13191 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13195 this.cells.each(function(c) {
13197 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13200 for (var e = 0; e < c.events.length; e++){
13201 var ev = c.events[e];
13202 var rows = ev.rows;
13204 for(var i = 0; i < rows.length; i++) {
13206 // how many rows should it span..
13209 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13210 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13212 unselectable : "on",
13215 cls: 'fc-event-inner',
13219 // cls: 'fc-event-time',
13220 // html : cells.length > 1 ? '' : ev.time
13224 cls: 'fc-event-title',
13225 html : String.format('{0}', ev.title)
13232 cls: 'ui-resizable-handle ui-resizable-e',
13233 html : '  '
13240 cfg.cls += ' fc-event-start';
13242 if ((i+1) == rows.length) {
13243 cfg.cls += ' fc-event-end';
13246 var ctr = _this.el.select('.fc-event-container',true).first();
13247 var cg = ctr.createChild(cfg);
13249 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13250 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13252 var r = (c.more.length) ? 1 : 0;
13253 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13254 cg.setWidth(ebox.right - sbox.x -2);
13256 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13257 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13258 cg.on('click', _this.onEventClick, _this, ev);
13269 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13270 style : 'position: absolute',
13271 unselectable : "on",
13274 cls: 'fc-event-inner',
13278 cls: 'fc-event-title',
13286 cls: 'ui-resizable-handle ui-resizable-e',
13287 html : '  '
13293 var ctr = _this.el.select('.fc-event-container',true).first();
13294 var cg = ctr.createChild(cfg);
13296 var sbox = c.select('.fc-day-content',true).first().getBox();
13297 var ebox = c.select('.fc-day-content',true).first().getBox();
13299 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13300 cg.setWidth(ebox.right - sbox.x -2);
13302 cg.on('click', _this.onMoreEventClick, _this, c.more);
13312 onEventEnter: function (e, el,event,d) {
13313 this.fireEvent('evententer', this, el, event);
13316 onEventLeave: function (e, el,event,d) {
13317 this.fireEvent('eventleave', this, el, event);
13320 onEventClick: function (e, el,event,d) {
13321 this.fireEvent('eventclick', this, el, event);
13324 onMonthChange: function () {
13328 onMoreEventClick: function(e, el, more)
13332 this.calpopover.placement = 'right';
13333 this.calpopover.setTitle('More');
13335 this.calpopover.setContent('');
13337 var ctr = this.calpopover.el.select('.popover-content', true).first();
13339 Roo.each(more, function(m){
13341 cls : 'fc-event-hori fc-event-draggable',
13344 var cg = ctr.createChild(cfg);
13346 cg.on('click', _this.onEventClick, _this, m);
13349 this.calpopover.show(el);
13354 onLoad: function ()
13356 this.calevents = [];
13359 if(this.store.getCount() > 0){
13360 this.store.data.each(function(d){
13363 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13364 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13365 time : d.data.start_time,
13366 title : d.data.title,
13367 description : d.data.description,
13368 venue : d.data.venue
13373 this.renderEvents();
13375 if(this.calevents.length && this.loadMask){
13376 this.maskEl.hide();
13380 onBeforeLoad: function()
13382 this.clearEvents();
13384 this.maskEl.show();
13398 * @class Roo.bootstrap.Popover
13399 * @extends Roo.bootstrap.Component
13400 * Bootstrap Popover class
13401 * @cfg {String} html contents of the popover (or false to use children..)
13402 * @cfg {String} title of popover (or false to hide)
13403 * @cfg {String} placement how it is placed
13404 * @cfg {String} trigger click || hover (or false to trigger manually)
13405 * @cfg {String} over what (parent or false to trigger manually.)
13408 * Create a new Popover
13409 * @param {Object} config The config object
13412 Roo.bootstrap.Popover = function(config){
13413 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13416 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13418 title: 'Fill in a title',
13421 placement : 'right',
13422 trigger : 'hover', // hover
13426 can_build_overlaid : false,
13428 getChildContainer : function()
13430 return this.el.select('.popover-content',true).first();
13433 getAutoCreate : function(){
13434 Roo.log('make popover?');
13436 cls : 'popover roo-dynamic',
13437 style: 'display:block',
13443 cls : 'popover-inner',
13447 cls: 'popover-title',
13451 cls : 'popover-content',
13462 setTitle: function(str)
13464 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13466 setContent: function(str)
13468 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13470 // as it get's added to the bottom of the page.
13471 onRender : function(ct, position)
13473 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13475 var cfg = Roo.apply({}, this.getAutoCreate());
13479 cfg.cls += ' ' + this.cls;
13482 cfg.style = this.style;
13484 Roo.log("adding to ")
13485 this.el = Roo.get(document.body).createChild(cfg, position);
13491 initEvents : function()
13493 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13494 this.el.enableDisplayMode('block');
13496 if (this.over === false) {
13499 if (this.triggers === false) {
13502 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13503 var triggers = this.trigger ? this.trigger.split(' ') : [];
13504 Roo.each(triggers, function(trigger) {
13506 if (trigger == 'click') {
13507 on_el.on('click', this.toggle, this);
13508 } else if (trigger != 'manual') {
13509 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13510 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13512 on_el.on(eventIn ,this.enter, this);
13513 on_el.on(eventOut, this.leave, this);
13524 toggle : function () {
13525 this.hoverState == 'in' ? this.leave() : this.enter();
13528 enter : function () {
13531 clearTimeout(this.timeout);
13533 this.hoverState = 'in'
13535 if (!this.delay || !this.delay.show) {
13540 this.timeout = setTimeout(function () {
13541 if (_t.hoverState == 'in') {
13544 }, this.delay.show)
13546 leave : function() {
13547 clearTimeout(this.timeout);
13549 this.hoverState = 'out'
13551 if (!this.delay || !this.delay.hide) {
13556 this.timeout = setTimeout(function () {
13557 if (_t.hoverState == 'out') {
13560 }, this.delay.hide)
13563 show : function (on_el)
13566 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13569 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13570 if (this.html !== false) {
13571 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13573 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13574 if (!this.title.length) {
13575 this.el.select('.popover-title',true).hide();
13578 var placement = typeof this.placement == 'function' ?
13579 this.placement.call(this, this.el, on_el) :
13582 var autoToken = /\s?auto?\s?/i;
13583 var autoPlace = autoToken.test(placement);
13585 placement = placement.replace(autoToken, '') || 'top';
13589 //this.el.setXY([0,0]);
13591 this.el.dom.style.display='block';
13592 this.el.addClass(placement);
13594 //this.el.appendTo(on_el);
13596 var p = this.getPosition();
13597 var box = this.el.getBox();
13602 var align = Roo.bootstrap.Popover.alignment[placement]
13603 this.el.alignTo(on_el, align[0],align[1]);
13604 //var arrow = this.el.select('.arrow',true).first();
13605 //arrow.set(align[2],
13607 this.el.addClass('in');
13608 this.hoverState = null;
13610 if (this.el.hasClass('fade')) {
13617 this.el.setXY([0,0]);
13618 this.el.removeClass('in');
13625 Roo.bootstrap.Popover.alignment = {
13626 'left' : ['r-l', [-10,0], 'right'],
13627 'right' : ['l-r', [10,0], 'left'],
13628 'bottom' : ['t-b', [0,10], 'top'],
13629 'top' : [ 'b-t', [0,-10], 'bottom']
13640 * @class Roo.bootstrap.Progress
13641 * @extends Roo.bootstrap.Component
13642 * Bootstrap Progress class
13643 * @cfg {Boolean} striped striped of the progress bar
13644 * @cfg {Boolean} active animated of the progress bar
13648 * Create a new Progress
13649 * @param {Object} config The config object
13652 Roo.bootstrap.Progress = function(config){
13653 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13656 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13661 getAutoCreate : function(){
13669 cfg.cls += ' progress-striped';
13673 cfg.cls += ' active';
13692 * @class Roo.bootstrap.ProgressBar
13693 * @extends Roo.bootstrap.Component
13694 * Bootstrap ProgressBar class
13695 * @cfg {Number} aria_valuenow aria-value now
13696 * @cfg {Number} aria_valuemin aria-value min
13697 * @cfg {Number} aria_valuemax aria-value max
13698 * @cfg {String} label label for the progress bar
13699 * @cfg {String} panel (success | info | warning | danger )
13700 * @cfg {String} role role of the progress bar
13701 * @cfg {String} sr_only text
13705 * Create a new ProgressBar
13706 * @param {Object} config The config object
13709 Roo.bootstrap.ProgressBar = function(config){
13710 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13713 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13717 aria_valuemax : 100,
13723 getAutoCreate : function()
13728 cls: 'progress-bar',
13729 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13741 cfg.role = this.role;
13744 if(this.aria_valuenow){
13745 cfg['aria-valuenow'] = this.aria_valuenow;
13748 if(this.aria_valuemin){
13749 cfg['aria-valuemin'] = this.aria_valuemin;
13752 if(this.aria_valuemax){
13753 cfg['aria-valuemax'] = this.aria_valuemax;
13756 if(this.label && !this.sr_only){
13757 cfg.html = this.label;
13761 cfg.cls += ' progress-bar-' + this.panel;
13767 update : function(aria_valuenow)
13769 this.aria_valuenow = aria_valuenow;
13771 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13786 * @class Roo.bootstrap.TabGroup
13787 * @extends Roo.bootstrap.Column
13788 * Bootstrap Column class
13789 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13790 * @cfg {Boolean} carousel true to make the group behave like a carousel
13793 * Create a new TabGroup
13794 * @param {Object} config The config object
13797 Roo.bootstrap.TabGroup = function(config){
13798 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13800 this.navId = Roo.id();
13803 Roo.bootstrap.TabGroup.register(this);
13807 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13811 getAutoCreate : function()
13813 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13815 cfg.cls += ' tab-content';
13817 if (this.carousel) {
13818 cfg.cls += ' carousel slide';
13820 cls : 'carousel-inner'
13827 getChildContainer : function()
13829 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13833 * register a Navigation item
13834 * @param {Roo.bootstrap.NavItem} the navitem to add
13836 register : function(item)
13838 this.tabs.push( item);
13839 item.navId = this.navId; // not really needed..
13843 getActivePanel : function()
13846 Roo.each(this.tabs, function(t) {
13856 getPanelByName : function(n)
13859 Roo.each(this.tabs, function(t) {
13860 if (t.tabId == n) {
13868 indexOfPanel : function(p)
13871 Roo.each(this.tabs, function(t,i) {
13872 if (t.tabId == p.tabId) {
13881 * show a specific panel
13882 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13883 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13885 showPanel : function (pan)
13890 if (typeof(pan) == 'number') {
13891 pan = this.tabs[pan];
13893 if (typeof(pan) == 'string') {
13894 pan = this.getPanelByName(pan);
13896 if (pan.tabId == this.getActivePanel().tabId) {
13899 var cur = this.getActivePanel();
13901 if (false === cur.fireEvent('beforedeactivate')) {
13907 if (this.carousel) {
13908 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13909 var lr = dir == 'next' ? 'left' : 'right';
13910 pan.el.addClass(dir); // or prev
13911 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13912 cur.el.addClass(lr); // or right
13913 pan.el.addClass(lr);
13914 cur.el.on('transitionend', function() {
13915 Roo.log("trans end?");
13917 pan.el.removeClass([lr,dir]);
13918 pan.setActive(true);
13920 cur.el.removeClass([lr]);
13921 cur.setActive(false);
13924 }, this, { single: true } );
13928 cur.setActive(false);
13929 pan.setActive(true);
13933 showPanelNext : function()
13935 var i = this.indexOfPanel(this.getActivePanel());
13936 if (i > this.tabs.length) {
13939 this.showPanel(this.tabs[i+1]);
13941 showPanelPrev : function()
13943 var i = this.indexOfPanel(this.getActivePanel());
13947 this.showPanel(this.tabs[i-1]);
13958 Roo.apply(Roo.bootstrap.TabGroup, {
13962 * register a Navigation Group
13963 * @param {Roo.bootstrap.NavGroup} the navgroup to add
13965 register : function(navgrp)
13967 this.groups[navgrp.navId] = navgrp;
13971 * fetch a Navigation Group based on the navigation ID
13972 * if one does not exist , it will get created.
13973 * @param {string} the navgroup to add
13974 * @returns {Roo.bootstrap.NavGroup} the navgroup
13976 get: function(navId) {
13977 if (typeof(this.groups[navId]) == 'undefined') {
13978 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
13980 return this.groups[navId] ;
13995 * @class Roo.bootstrap.TabPanel
13996 * @extends Roo.bootstrap.Component
13997 * Bootstrap TabPanel class
13998 * @cfg {Boolean} active panel active
13999 * @cfg {String} html panel content
14000 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14001 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14005 * Create a new TabPanel
14006 * @param {Object} config The config object
14009 Roo.bootstrap.TabPanel = function(config){
14010 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14014 * Fires when the active status changes
14015 * @param {Roo.bootstrap.TabPanel} this
14016 * @param {Boolean} state the new state
14021 * @event beforedeactivate
14022 * Fires before a tab is de-activated - can be used to do validation on a form.
14023 * @param {Roo.bootstrap.TabPanel} this
14024 * @return {Boolean} false if there is an error
14027 'beforedeactivate': true
14030 this.tabId = this.tabId || Roo.id();
14034 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14041 getAutoCreate : function(){
14044 // item is needed for carousel - not sure if it has any effect otherwise
14045 cls: 'tab-pane item',
14046 html: this.html || ''
14050 cfg.cls += ' active';
14054 cfg.tabId = this.tabId;
14061 initEvents: function()
14063 Roo.log('-------- init events on tab panel ---------');
14065 var p = this.parent();
14066 this.navId = this.navId || p.navId;
14068 if (typeof(this.navId) != 'undefined') {
14069 // not really needed.. but just in case.. parent should be a NavGroup.
14070 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14071 Roo.log(['register', tg, this]);
14077 onRender : function(ct, position)
14079 // Roo.log("Call onRender: " + this.xtype);
14081 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14089 setActive: function(state)
14091 Roo.log("panel - set active " + this.tabId + "=" + state);
14093 this.active = state;
14095 this.el.removeClass('active');
14097 } else if (!this.el.hasClass('active')) {
14098 this.el.addClass('active');
14100 this.fireEvent('changed', this, state);
14117 * @class Roo.bootstrap.DateField
14118 * @extends Roo.bootstrap.Input
14119 * Bootstrap DateField class
14120 * @cfg {Number} weekStart default 0
14121 * @cfg {Number} weekStart default 0
14122 * @cfg {Number} viewMode default empty, (months|years)
14123 * @cfg {Number} minViewMode default empty, (months|years)
14124 * @cfg {Number} startDate default -Infinity
14125 * @cfg {Number} endDate default Infinity
14126 * @cfg {Boolean} todayHighlight default false
14127 * @cfg {Boolean} todayBtn default false
14128 * @cfg {Boolean} calendarWeeks default false
14129 * @cfg {Object} daysOfWeekDisabled default empty
14131 * @cfg {Boolean} keyboardNavigation default true
14132 * @cfg {String} language default en
14135 * Create a new DateField
14136 * @param {Object} config The config object
14139 Roo.bootstrap.DateField = function(config){
14140 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14144 * Fires when this field show.
14145 * @param {Roo.bootstrap.DateField} this
14146 * @param {Mixed} date The date value
14151 * Fires when this field hide.
14152 * @param {Roo.bootstrap.DateField} this
14153 * @param {Mixed} date The date value
14158 * Fires when select a date.
14159 * @param {Roo.bootstrap.DateField} this
14160 * @param {Mixed} date The date value
14166 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14169 * @cfg {String} format
14170 * The default date format string which can be overriden for localization support. The format must be
14171 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14175 * @cfg {String} altFormats
14176 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14177 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14179 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14187 todayHighlight : false,
14193 keyboardNavigation: true,
14195 calendarWeeks: false,
14197 startDate: -Infinity,
14201 daysOfWeekDisabled: [],
14205 UTCDate: function()
14207 return new Date(Date.UTC.apply(Date, arguments));
14210 UTCToday: function()
14212 var today = new Date();
14213 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14216 getDate: function() {
14217 var d = this.getUTCDate();
14218 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14221 getUTCDate: function() {
14225 setDate: function(d) {
14226 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14229 setUTCDate: function(d) {
14231 this.setValue(this.formatDate(this.date));
14234 onRender: function(ct, position)
14237 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14239 this.language = this.language || 'en';
14240 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14241 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14243 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14244 this.format = this.format || 'm/d/y';
14245 this.isInline = false;
14246 this.isInput = true;
14247 this.component = this.el.select('.add-on', true).first() || false;
14248 this.component = (this.component && this.component.length === 0) ? false : this.component;
14249 this.hasInput = this.component && this.inputEL().length;
14251 if (typeof(this.minViewMode === 'string')) {
14252 switch (this.minViewMode) {
14254 this.minViewMode = 1;
14257 this.minViewMode = 2;
14260 this.minViewMode = 0;
14265 if (typeof(this.viewMode === 'string')) {
14266 switch (this.viewMode) {
14279 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14281 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14283 this.picker().on('mousedown', this.onMousedown, this);
14284 this.picker().on('click', this.onClick, this);
14286 this.picker().addClass('datepicker-dropdown');
14288 this.startViewMode = this.viewMode;
14291 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14292 if(!this.calendarWeeks){
14297 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14298 v.attr('colspan', function(i, val){
14299 return parseInt(val) + 1;
14304 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14306 this.setStartDate(this.startDate);
14307 this.setEndDate(this.endDate);
14309 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14316 if(this.isInline) {
14321 picker : function()
14323 return this.el.select('.datepicker', true).first();
14326 fillDow: function()
14328 var dowCnt = this.weekStart;
14337 if(this.calendarWeeks){
14345 while (dowCnt < this.weekStart + 7) {
14349 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14353 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14356 fillMonths: function()
14359 var months = this.picker().select('>.datepicker-months td', true).first();
14361 months.dom.innerHTML = '';
14367 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14370 months.createChild(month);
14378 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14380 if (this.date < this.startDate) {
14381 this.viewDate = new Date(this.startDate);
14382 } else if (this.date > this.endDate) {
14383 this.viewDate = new Date(this.endDate);
14385 this.viewDate = new Date(this.date);
14393 var d = new Date(this.viewDate),
14394 year = d.getUTCFullYear(),
14395 month = d.getUTCMonth(),
14396 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14397 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14398 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14399 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14400 currentDate = this.date && this.date.valueOf(),
14401 today = this.UTCToday();
14403 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14405 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14407 // this.picker.select('>tfoot th.today').
14408 // .text(dates[this.language].today)
14409 // .toggle(this.todayBtn !== false);
14411 this.updateNavArrows();
14414 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14416 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14418 prevMonth.setUTCDate(day);
14420 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14422 var nextMonth = new Date(prevMonth);
14424 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14426 nextMonth = nextMonth.valueOf();
14428 var fillMonths = false;
14430 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14432 while(prevMonth.valueOf() < nextMonth) {
14435 if (prevMonth.getUTCDay() === this.weekStart) {
14437 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14445 if(this.calendarWeeks){
14446 // ISO 8601: First week contains first thursday.
14447 // ISO also states week starts on Monday, but we can be more abstract here.
14449 // Start of current week: based on weekstart/current date
14450 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14451 // Thursday of this week
14452 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14453 // First Thursday of year, year from thursday
14454 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14455 // Calendar week: ms between thursdays, div ms per day, div 7 days
14456 calWeek = (th - yth) / 864e5 / 7 + 1;
14458 fillMonths.cn.push({
14466 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14468 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14471 if (this.todayHighlight &&
14472 prevMonth.getUTCFullYear() == today.getFullYear() &&
14473 prevMonth.getUTCMonth() == today.getMonth() &&
14474 prevMonth.getUTCDate() == today.getDate()) {
14475 clsName += ' today';
14478 if (currentDate && prevMonth.valueOf() === currentDate) {
14479 clsName += ' active';
14482 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14483 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14484 clsName += ' disabled';
14487 fillMonths.cn.push({
14489 cls: 'day ' + clsName,
14490 html: prevMonth.getDate()
14493 prevMonth.setDate(prevMonth.getDate()+1);
14496 var currentYear = this.date && this.date.getUTCFullYear();
14497 var currentMonth = this.date && this.date.getUTCMonth();
14499 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14501 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14502 v.removeClass('active');
14504 if(currentYear === year && k === currentMonth){
14505 v.addClass('active');
14508 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14509 v.addClass('disabled');
14515 year = parseInt(year/10, 10) * 10;
14517 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14519 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14522 for (var i = -1; i < 11; i++) {
14523 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14525 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14533 showMode: function(dir)
14536 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14538 Roo.each(this.picker().select('>div',true).elements, function(v){
14539 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14542 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14547 if(this.isInline) return;
14549 this.picker().removeClass(['bottom', 'top']);
14551 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14553 * place to the top of element!
14557 this.picker().addClass('top');
14558 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14563 this.picker().addClass('bottom');
14565 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14568 parseDate : function(value)
14570 if(!value || value instanceof Date){
14573 var v = Date.parseDate(value, this.format);
14574 if (!v && this.useIso) {
14575 v = Date.parseDate(value, 'Y-m-d');
14577 if(!v && this.altFormats){
14578 if(!this.altFormatsArray){
14579 this.altFormatsArray = this.altFormats.split("|");
14581 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14582 v = Date.parseDate(value, this.altFormatsArray[i]);
14588 formatDate : function(date, fmt)
14590 return (!date || !(date instanceof Date)) ?
14591 date : date.dateFormat(fmt || this.format);
14594 onFocus : function()
14596 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14600 onBlur : function()
14602 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14604 var d = this.inputEl().getValue();
14615 this.picker().show();
14619 this.fireEvent('show', this, this.date);
14624 if(this.isInline) return;
14625 this.picker().hide();
14626 this.viewMode = this.startViewMode;
14629 this.fireEvent('hide', this, this.date);
14633 onMousedown: function(e)
14635 e.stopPropagation();
14636 e.preventDefault();
14641 Roo.bootstrap.DateField.superclass.keyup.call(this);
14645 setValue: function(v)
14647 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14649 var d = new Date(v);
14651 if(isNaN(d.getTime())){
14655 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14659 this.fireEvent('select', this, this.date);
14663 getValue: function()
14665 return this.formatDate(this.date);
14668 fireKey: function(e)
14670 if (!this.picker().isVisible()){
14671 if (e.keyCode == 27) // allow escape to hide and re-show picker
14676 var dateChanged = false,
14678 newDate, newViewDate;
14683 e.preventDefault();
14687 if (!this.keyboardNavigation) break;
14688 dir = e.keyCode == 37 ? -1 : 1;
14691 newDate = this.moveYear(this.date, dir);
14692 newViewDate = this.moveYear(this.viewDate, dir);
14693 } else if (e.shiftKey){
14694 newDate = this.moveMonth(this.date, dir);
14695 newViewDate = this.moveMonth(this.viewDate, dir);
14697 newDate = new Date(this.date);
14698 newDate.setUTCDate(this.date.getUTCDate() + dir);
14699 newViewDate = new Date(this.viewDate);
14700 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14702 if (this.dateWithinRange(newDate)){
14703 this.date = newDate;
14704 this.viewDate = newViewDate;
14705 this.setValue(this.formatDate(this.date));
14707 e.preventDefault();
14708 dateChanged = true;
14713 if (!this.keyboardNavigation) break;
14714 dir = e.keyCode == 38 ? -1 : 1;
14716 newDate = this.moveYear(this.date, dir);
14717 newViewDate = this.moveYear(this.viewDate, dir);
14718 } else if (e.shiftKey){
14719 newDate = this.moveMonth(this.date, dir);
14720 newViewDate = this.moveMonth(this.viewDate, dir);
14722 newDate = new Date(this.date);
14723 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14724 newViewDate = new Date(this.viewDate);
14725 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14727 if (this.dateWithinRange(newDate)){
14728 this.date = newDate;
14729 this.viewDate = newViewDate;
14730 this.setValue(this.formatDate(this.date));
14732 e.preventDefault();
14733 dateChanged = true;
14737 this.setValue(this.formatDate(this.date));
14739 e.preventDefault();
14742 this.setValue(this.formatDate(this.date));
14756 onClick: function(e)
14758 e.stopPropagation();
14759 e.preventDefault();
14761 var target = e.getTarget();
14763 if(target.nodeName.toLowerCase() === 'i'){
14764 target = Roo.get(target).dom.parentNode;
14767 var nodeName = target.nodeName;
14768 var className = target.className;
14769 var html = target.innerHTML;
14771 switch(nodeName.toLowerCase()) {
14773 switch(className) {
14779 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14780 switch(this.viewMode){
14782 this.viewDate = this.moveMonth(this.viewDate, dir);
14786 this.viewDate = this.moveYear(this.viewDate, dir);
14792 var date = new Date();
14793 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14795 this.setValue(this.formatDate(this.date));
14802 if (className.indexOf('disabled') === -1) {
14803 this.viewDate.setUTCDate(1);
14804 if (className.indexOf('month') !== -1) {
14805 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14807 var year = parseInt(html, 10) || 0;
14808 this.viewDate.setUTCFullYear(year);
14817 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14818 var day = parseInt(html, 10) || 1;
14819 var year = this.viewDate.getUTCFullYear(),
14820 month = this.viewDate.getUTCMonth();
14822 if (className.indexOf('old') !== -1) {
14829 } else if (className.indexOf('new') !== -1) {
14837 this.date = this.UTCDate(year, month, day,0,0,0,0);
14838 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14840 this.setValue(this.formatDate(this.date));
14847 setStartDate: function(startDate)
14849 this.startDate = startDate || -Infinity;
14850 if (this.startDate !== -Infinity) {
14851 this.startDate = this.parseDate(this.startDate);
14854 this.updateNavArrows();
14857 setEndDate: function(endDate)
14859 this.endDate = endDate || Infinity;
14860 if (this.endDate !== Infinity) {
14861 this.endDate = this.parseDate(this.endDate);
14864 this.updateNavArrows();
14867 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14869 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14870 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14871 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14873 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14874 return parseInt(d, 10);
14877 this.updateNavArrows();
14880 updateNavArrows: function()
14882 var d = new Date(this.viewDate),
14883 year = d.getUTCFullYear(),
14884 month = d.getUTCMonth();
14886 Roo.each(this.picker().select('.prev', true).elements, function(v){
14888 switch (this.viewMode) {
14891 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14897 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14904 Roo.each(this.picker().select('.next', true).elements, function(v){
14906 switch (this.viewMode) {
14909 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14915 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14923 moveMonth: function(date, dir)
14925 if (!dir) return date;
14926 var new_date = new Date(date.valueOf()),
14927 day = new_date.getUTCDate(),
14928 month = new_date.getUTCMonth(),
14929 mag = Math.abs(dir),
14931 dir = dir > 0 ? 1 : -1;
14934 // If going back one month, make sure month is not current month
14935 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14937 return new_date.getUTCMonth() == month;
14939 // If going forward one month, make sure month is as expected
14940 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14942 return new_date.getUTCMonth() != new_month;
14944 new_month = month + dir;
14945 new_date.setUTCMonth(new_month);
14946 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14947 if (new_month < 0 || new_month > 11)
14948 new_month = (new_month + 12) % 12;
14950 // For magnitudes >1, move one month at a time...
14951 for (var i=0; i<mag; i++)
14952 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14953 new_date = this.moveMonth(new_date, dir);
14954 // ...then reset the day, keeping it in the new month
14955 new_month = new_date.getUTCMonth();
14956 new_date.setUTCDate(day);
14958 return new_month != new_date.getUTCMonth();
14961 // Common date-resetting loop -- if date is beyond end of month, make it
14964 new_date.setUTCDate(--day);
14965 new_date.setUTCMonth(new_month);
14970 moveYear: function(date, dir)
14972 return this.moveMonth(date, dir*12);
14975 dateWithinRange: function(date)
14977 return date >= this.startDate && date <= this.endDate;
14983 this.picker().remove();
14988 Roo.apply(Roo.bootstrap.DateField, {
14999 html: '<i class="fa fa-arrow-left"/>'
15009 html: '<i class="fa fa-arrow-right"/>'
15051 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15052 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15053 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15054 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15055 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15068 navFnc: 'FullYear',
15073 navFnc: 'FullYear',
15078 Roo.apply(Roo.bootstrap.DateField, {
15082 cls: 'datepicker dropdown-menu',
15086 cls: 'datepicker-days',
15090 cls: 'table-condensed',
15092 Roo.bootstrap.DateField.head,
15096 Roo.bootstrap.DateField.footer
15103 cls: 'datepicker-months',
15107 cls: 'table-condensed',
15109 Roo.bootstrap.DateField.head,
15110 Roo.bootstrap.DateField.content,
15111 Roo.bootstrap.DateField.footer
15118 cls: 'datepicker-years',
15122 cls: 'table-condensed',
15124 Roo.bootstrap.DateField.head,
15125 Roo.bootstrap.DateField.content,
15126 Roo.bootstrap.DateField.footer
15145 * @class Roo.bootstrap.TimeField
15146 * @extends Roo.bootstrap.Input
15147 * Bootstrap DateField class
15151 * Create a new TimeField
15152 * @param {Object} config The config object
15155 Roo.bootstrap.TimeField = function(config){
15156 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15160 * Fires when this field show.
15161 * @param {Roo.bootstrap.DateField} this
15162 * @param {Mixed} date The date value
15167 * Fires when this field hide.
15168 * @param {Roo.bootstrap.DateField} this
15169 * @param {Mixed} date The date value
15174 * Fires when select a date.
15175 * @param {Roo.bootstrap.DateField} this
15176 * @param {Mixed} date The date value
15182 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15185 * @cfg {String} format
15186 * The default time format string which can be overriden for localization support. The format must be
15187 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15191 onRender: function(ct, position)
15194 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15196 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15198 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15200 this.pop = this.picker().select('>.datepicker-time',true).first();
15201 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15203 this.picker().on('mousedown', this.onMousedown, this);
15204 this.picker().on('click', this.onClick, this);
15206 this.picker().addClass('datepicker-dropdown');
15211 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15212 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15213 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15214 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15215 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15216 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15220 fireKey: function(e){
15221 if (!this.picker().isVisible()){
15222 if (e.keyCode == 27) // allow escape to hide and re-show picker
15227 e.preventDefault();
15235 this.onTogglePeriod();
15238 this.onIncrementMinutes();
15241 this.onDecrementMinutes();
15250 onClick: function(e) {
15251 e.stopPropagation();
15252 e.preventDefault();
15255 picker : function()
15257 return this.el.select('.datepicker', true).first();
15260 fillTime: function()
15262 var time = this.pop.select('tbody', true).first();
15264 time.dom.innerHTML = '';
15279 cls: 'hours-up glyphicon glyphicon-chevron-up'
15299 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15320 cls: 'timepicker-hour',
15335 cls: 'timepicker-minute',
15350 cls: 'btn btn-primary period',
15372 cls: 'hours-down glyphicon glyphicon-chevron-down'
15392 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15410 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15417 var hours = this.time.getHours();
15418 var minutes = this.time.getMinutes();
15431 hours = hours - 12;
15435 hours = '0' + hours;
15439 minutes = '0' + minutes;
15442 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15443 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15444 this.pop.select('button', true).first().dom.innerHTML = period;
15450 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15452 var cls = ['bottom'];
15454 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15461 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15466 this.picker().addClass(cls.join('-'));
15470 Roo.each(cls, function(c){
15472 _this.picker().setTop(_this.inputEl().getHeight());
15476 _this.picker().setTop(0 - _this.picker().getHeight());
15481 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15485 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15492 onFocus : function()
15494 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15498 onBlur : function()
15500 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15506 this.picker().show();
15511 this.fireEvent('show', this, this.date);
15516 this.picker().hide();
15519 this.fireEvent('hide', this, this.date);
15522 setTime : function()
15525 this.setValue(this.time.format(this.format));
15527 this.fireEvent('select', this, this.date);
15532 onMousedown: function(e){
15533 e.stopPropagation();
15534 e.preventDefault();
15537 onIncrementHours: function()
15539 Roo.log('onIncrementHours');
15540 this.time = this.time.add(Date.HOUR, 1);
15545 onDecrementHours: function()
15547 Roo.log('onDecrementHours');
15548 this.time = this.time.add(Date.HOUR, -1);
15552 onIncrementMinutes: function()
15554 Roo.log('onIncrementMinutes');
15555 this.time = this.time.add(Date.MINUTE, 1);
15559 onDecrementMinutes: function()
15561 Roo.log('onDecrementMinutes');
15562 this.time = this.time.add(Date.MINUTE, -1);
15566 onTogglePeriod: function()
15568 Roo.log('onTogglePeriod');
15569 this.time = this.time.add(Date.HOUR, 12);
15576 Roo.apply(Roo.bootstrap.TimeField, {
15606 cls: 'btn btn-info ok',
15618 Roo.apply(Roo.bootstrap.TimeField, {
15622 cls: 'datepicker dropdown-menu',
15626 cls: 'datepicker-time',
15630 cls: 'table-condensed',
15632 Roo.bootstrap.TimeField.content,
15633 Roo.bootstrap.TimeField.footer
15652 * @class Roo.bootstrap.CheckBox
15653 * @extends Roo.bootstrap.Input
15654 * Bootstrap CheckBox class
15656 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15657 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15658 * @cfg {String} boxLabel The text that appears beside the checkbox
15659 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15660 * @cfg {Boolean} checked initnal the element
15664 * Create a new CheckBox
15665 * @param {Object} config The config object
15668 Roo.bootstrap.CheckBox = function(config){
15669 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15674 * Fires when the element is checked or unchecked.
15675 * @param {Roo.bootstrap.CheckBox} this This input
15676 * @param {Boolean} checked The new checked value
15682 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15684 inputType: 'checkbox',
15691 getAutoCreate : function()
15693 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15699 cfg.cls = 'form-group checkbox' //input-group
15707 type : this.inputType,
15708 value : (!this.checked) ? this.valueOff : this.inputValue,
15709 cls : 'roo-checkbox', //'form-box',
15710 placeholder : this.placeholder || ''
15714 if (this.weight) { // Validity check?
15715 cfg.cls += " checkbox-" + this.weight;
15718 if (this.disabled) {
15719 input.disabled=true;
15723 input.checked = this.checked;
15727 input.name = this.name;
15731 input.cls += ' input-' + this.size;
15735 ['xs','sm','md','lg'].map(function(size){
15736 if (settings[size]) {
15737 cfg.cls += ' col-' + size + '-' + settings[size];
15743 var inputblock = input;
15748 if (this.before || this.after) {
15751 cls : 'input-group',
15755 inputblock.cn.push({
15757 cls : 'input-group-addon',
15761 inputblock.cn.push(input);
15763 inputblock.cn.push({
15765 cls : 'input-group-addon',
15772 if (align ==='left' && this.fieldLabel.length) {
15773 Roo.log("left and has label");
15779 cls : 'control-label col-md-' + this.labelWidth,
15780 html : this.fieldLabel
15784 cls : "col-md-" + (12 - this.labelWidth),
15791 } else if ( this.fieldLabel.length) {
15796 tag: this.boxLabel ? 'span' : 'label',
15798 cls: 'control-label box-input-label',
15799 //cls : 'input-group-addon',
15800 html : this.fieldLabel
15810 Roo.log(" no label && no align");
15811 cfg.cn = [ inputblock ] ;
15820 html: this.boxLabel
15832 * return the real input element.
15834 inputEl: function ()
15836 return this.el.select('input.roo-checkbox',true).first();
15841 return this.el.select('label.control-label',true).first();
15844 initEvents : function()
15846 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15848 this.inputEl().on('click', this.onClick, this);
15852 onClick : function()
15854 this.setChecked(!this.checked);
15857 setChecked : function(state,suppressEvent)
15859 this.checked = state;
15861 this.inputEl().dom.checked = state;
15863 if(suppressEvent !== true){
15864 this.fireEvent('check', this, state);
15867 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15871 setValue : function(v,suppressEvent)
15873 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15887 * @class Roo.bootstrap.Radio
15888 * @extends Roo.bootstrap.CheckBox
15889 * Bootstrap Radio class
15892 * Create a new Radio
15893 * @param {Object} config The config object
15896 Roo.bootstrap.Radio = function(config){
15897 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15901 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15903 inputType: 'radio',
15907 getAutoCreate : function()
15909 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15915 cfg.cls = 'form-group radio' //input-group
15920 type : this.inputType,
15921 value : (!this.checked) ? this.valueOff : this.inputValue,
15923 placeholder : this.placeholder || ''
15926 if (this.weight) { // Validity check?
15927 cfg.cls += " radio-" + this.weight;
15929 if (this.disabled) {
15930 input.disabled=true;
15934 input.checked = this.checked;
15938 input.name = this.name;
15942 input.cls += ' input-' + this.size;
15946 ['xs','sm','md','lg'].map(function(size){
15947 if (settings[size]) {
15948 cfg.cls += ' col-' + size + '-' + settings[size];
15952 var inputblock = input;
15954 if (this.before || this.after) {
15957 cls : 'input-group',
15961 inputblock.cn.push({
15963 cls : 'input-group-addon',
15967 inputblock.cn.push(input);
15969 inputblock.cn.push({
15971 cls : 'input-group-addon',
15978 if (align ==='left' && this.fieldLabel.length) {
15979 Roo.log("left and has label");
15985 cls : 'control-label col-md-' + this.labelWidth,
15986 html : this.fieldLabel
15990 cls : "col-md-" + (12 - this.labelWidth),
15997 } else if ( this.fieldLabel.length) {
16004 cls: 'control-label box-input-label',
16005 //cls : 'input-group-addon',
16006 html : this.fieldLabel
16016 Roo.log(" no label && no align");
16031 html: this.boxLabel
16038 inputEl: function ()
16040 return this.el.select('input.roo-radio',true).first();
16042 onClick : function()
16044 this.setChecked(true);
16047 setChecked : function(state,suppressEvent)
16050 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16051 v.dom.checked = false;
16055 this.checked = state;
16056 this.inputEl().dom.checked = state;
16058 if(suppressEvent !== true){
16059 this.fireEvent('check', this, state);
16062 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16066 getGroupValue : function()
16069 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16070 if(v.dom.checked == true){
16071 value = v.dom.value;
16079 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16080 * @return {Mixed} value The field value
16082 getValue : function(){
16083 return this.getGroupValue();
16089 //<script type="text/javascript">
16092 * Based Ext JS Library 1.1.1
16093 * Copyright(c) 2006-2007, Ext JS, LLC.
16099 * @class Roo.HtmlEditorCore
16100 * @extends Roo.Component
16101 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16103 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16106 Roo.HtmlEditorCore = function(config){
16109 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16112 * @event initialize
16113 * Fires when the editor is fully initialized (including the iframe)
16114 * @param {Roo.HtmlEditorCore} this
16119 * Fires when the editor is first receives the focus. Any insertion must wait
16120 * until after this event.
16121 * @param {Roo.HtmlEditorCore} this
16125 * @event beforesync
16126 * Fires before the textarea is updated with content from the editor iframe. Return false
16127 * to cancel the sync.
16128 * @param {Roo.HtmlEditorCore} this
16129 * @param {String} html
16133 * @event beforepush
16134 * Fires before the iframe editor is updated with content from the textarea. Return false
16135 * to cancel the push.
16136 * @param {Roo.HtmlEditorCore} this
16137 * @param {String} html
16142 * Fires when the textarea is updated with content from the editor iframe.
16143 * @param {Roo.HtmlEditorCore} this
16144 * @param {String} html
16149 * Fires when the iframe editor is updated with content from the textarea.
16150 * @param {Roo.HtmlEditorCore} this
16151 * @param {String} html
16156 * @event editorevent
16157 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16158 * @param {Roo.HtmlEditorCore} this
16166 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16170 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16176 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16181 * @cfg {Number} height (in pixels)
16185 * @cfg {Number} width (in pixels)
16190 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16193 stylesheets: false,
16198 // private properties
16199 validationEvent : false,
16201 initialized : false,
16203 sourceEditMode : false,
16204 onFocus : Roo.emptyFn,
16206 hideMode:'offsets',
16214 * Protected method that will not generally be called directly. It
16215 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16216 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16218 getDocMarkup : function(){
16221 Roo.log(this.stylesheets);
16223 // inherit styels from page...??
16224 if (this.stylesheets === false) {
16226 Roo.get(document.head).select('style').each(function(node) {
16227 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16230 Roo.get(document.head).select('link').each(function(node) {
16231 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16234 } else if (!this.stylesheets.length) {
16236 st = '<style type="text/css">' +
16237 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16240 Roo.each(this.stylesheets, function(s) {
16241 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16246 st += '<style type="text/css">' +
16247 'IMG { cursor: pointer } ' +
16251 return '<html><head>' + st +
16252 //<style type="text/css">' +
16253 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16255 ' </head><body class="roo-htmleditor-body"></body></html>';
16259 onRender : function(ct, position)
16262 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16263 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16266 this.el.dom.style.border = '0 none';
16267 this.el.dom.setAttribute('tabIndex', -1);
16268 this.el.addClass('x-hidden hide');
16272 if(Roo.isIE){ // fix IE 1px bogus margin
16273 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16277 this.frameId = Roo.id();
16281 var iframe = this.owner.wrap.createChild({
16283 cls: 'form-control', // bootstrap..
16285 name: this.frameId,
16286 frameBorder : 'no',
16287 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16292 this.iframe = iframe.dom;
16294 this.assignDocWin();
16296 this.doc.designMode = 'on';
16299 this.doc.write(this.getDocMarkup());
16303 var task = { // must defer to wait for browser to be ready
16305 //console.log("run task?" + this.doc.readyState);
16306 this.assignDocWin();
16307 if(this.doc.body || this.doc.readyState == 'complete'){
16309 this.doc.designMode="on";
16313 Roo.TaskMgr.stop(task);
16314 this.initEditor.defer(10, this);
16321 Roo.TaskMgr.start(task);
16328 onResize : function(w, h)
16330 Roo.log('resize: ' +w + ',' + h );
16331 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16335 if(typeof w == 'number'){
16337 this.iframe.style.width = w + 'px';
16339 if(typeof h == 'number'){
16341 this.iframe.style.height = h + 'px';
16343 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16350 * Toggles the editor between standard and source edit mode.
16351 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16353 toggleSourceEdit : function(sourceEditMode){
16355 this.sourceEditMode = sourceEditMode === true;
16357 if(this.sourceEditMode){
16359 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16362 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16363 //this.iframe.className = '';
16366 //this.setSize(this.owner.wrap.getSize());
16367 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16374 * Protected method that will not generally be called directly. If you need/want
16375 * custom HTML cleanup, this is the method you should override.
16376 * @param {String} html The HTML to be cleaned
16377 * return {String} The cleaned HTML
16379 cleanHtml : function(html){
16380 html = String(html);
16381 if(html.length > 5){
16382 if(Roo.isSafari){ // strip safari nonsense
16383 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16386 if(html == ' '){
16393 * HTML Editor -> Textarea
16394 * Protected method that will not generally be called directly. Syncs the contents
16395 * of the editor iframe with the textarea.
16397 syncValue : function(){
16398 if(this.initialized){
16399 var bd = (this.doc.body || this.doc.documentElement);
16400 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16401 var html = bd.innerHTML;
16403 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16404 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16406 html = '<div style="'+m[0]+'">' + html + '</div>';
16409 html = this.cleanHtml(html);
16410 // fix up the special chars.. normaly like back quotes in word...
16411 // however we do not want to do this with chinese..
16412 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16413 var cc = b.charCodeAt();
16415 (cc >= 0x4E00 && cc < 0xA000 ) ||
16416 (cc >= 0x3400 && cc < 0x4E00 ) ||
16417 (cc >= 0xf900 && cc < 0xfb00 )
16423 if(this.owner.fireEvent('beforesync', this, html) !== false){
16424 this.el.dom.value = html;
16425 this.owner.fireEvent('sync', this, html);
16431 * Protected method that will not generally be called directly. Pushes the value of the textarea
16432 * into the iframe editor.
16434 pushValue : function(){
16435 if(this.initialized){
16436 var v = this.el.dom.value.trim();
16438 // if(v.length < 1){
16442 if(this.owner.fireEvent('beforepush', this, v) !== false){
16443 var d = (this.doc.body || this.doc.documentElement);
16445 this.cleanUpPaste();
16446 this.el.dom.value = d.innerHTML;
16447 this.owner.fireEvent('push', this, v);
16453 deferFocus : function(){
16454 this.focus.defer(10, this);
16458 focus : function(){
16459 if(this.win && !this.sourceEditMode){
16466 assignDocWin: function()
16468 var iframe = this.iframe;
16471 this.doc = iframe.contentWindow.document;
16472 this.win = iframe.contentWindow;
16474 if (!Roo.get(this.frameId)) {
16477 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16478 this.win = Roo.get(this.frameId).dom.contentWindow;
16483 initEditor : function(){
16484 //console.log("INIT EDITOR");
16485 this.assignDocWin();
16489 this.doc.designMode="on";
16491 this.doc.write(this.getDocMarkup());
16494 var dbody = (this.doc.body || this.doc.documentElement);
16495 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16496 // this copies styles from the containing element into thsi one..
16497 // not sure why we need all of this..
16498 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16500 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16501 //ss['background-attachment'] = 'fixed'; // w3c
16502 dbody.bgProperties = 'fixed'; // ie
16503 //Roo.DomHelper.applyStyles(dbody, ss);
16504 Roo.EventManager.on(this.doc, {
16505 //'mousedown': this.onEditorEvent,
16506 'mouseup': this.onEditorEvent,
16507 'dblclick': this.onEditorEvent,
16508 'click': this.onEditorEvent,
16509 'keyup': this.onEditorEvent,
16514 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16516 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16517 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16519 this.initialized = true;
16521 this.owner.fireEvent('initialize', this);
16526 onDestroy : function(){
16532 //for (var i =0; i < this.toolbars.length;i++) {
16533 // // fixme - ask toolbars for heights?
16534 // this.toolbars[i].onDestroy();
16537 //this.wrap.dom.innerHTML = '';
16538 //this.wrap.remove();
16543 onFirstFocus : function(){
16545 this.assignDocWin();
16548 this.activated = true;
16551 if(Roo.isGecko){ // prevent silly gecko errors
16553 var s = this.win.getSelection();
16554 if(!s.focusNode || s.focusNode.nodeType != 3){
16555 var r = s.getRangeAt(0);
16556 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16561 this.execCmd('useCSS', true);
16562 this.execCmd('styleWithCSS', false);
16565 this.owner.fireEvent('activate', this);
16569 adjustFont: function(btn){
16570 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16571 //if(Roo.isSafari){ // safari
16574 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16575 if(Roo.isSafari){ // safari
16576 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16577 v = (v < 10) ? 10 : v;
16578 v = (v > 48) ? 48 : v;
16579 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16584 v = Math.max(1, v+adjust);
16586 this.execCmd('FontSize', v );
16589 onEditorEvent : function(e){
16590 this.owner.fireEvent('editorevent', this, e);
16591 // this.updateToolbar();
16592 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16595 insertTag : function(tg)
16597 // could be a bit smarter... -> wrap the current selected tRoo..
16598 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16600 range = this.createRange(this.getSelection());
16601 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16602 wrappingNode.appendChild(range.extractContents());
16603 range.insertNode(wrappingNode);
16610 this.execCmd("formatblock", tg);
16614 insertText : function(txt)
16618 var range = this.createRange();
16619 range.deleteContents();
16620 //alert(Sender.getAttribute('label'));
16622 range.insertNode(this.doc.createTextNode(txt));
16628 * Executes a Midas editor command on the editor document and performs necessary focus and
16629 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16630 * @param {String} cmd The Midas command
16631 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16633 relayCmd : function(cmd, value){
16635 this.execCmd(cmd, value);
16636 this.owner.fireEvent('editorevent', this);
16637 //this.updateToolbar();
16638 this.owner.deferFocus();
16642 * Executes a Midas editor command directly on the editor document.
16643 * For visual commands, you should use {@link #relayCmd} instead.
16644 * <b>This should only be called after the editor is initialized.</b>
16645 * @param {String} cmd The Midas command
16646 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16648 execCmd : function(cmd, value){
16649 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16656 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16658 * @param {String} text | dom node..
16660 insertAtCursor : function(text)
16665 if(!this.activated){
16671 var r = this.doc.selection.createRange();
16682 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16686 // from jquery ui (MIT licenced)
16688 var win = this.win;
16690 if (win.getSelection && win.getSelection().getRangeAt) {
16691 range = win.getSelection().getRangeAt(0);
16692 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16693 range.insertNode(node);
16694 } else if (win.document.selection && win.document.selection.createRange) {
16695 // no firefox support
16696 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16697 win.document.selection.createRange().pasteHTML(txt);
16699 // no firefox support
16700 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16701 this.execCmd('InsertHTML', txt);
16710 mozKeyPress : function(e){
16712 var c = e.getCharCode(), cmd;
16715 c = String.fromCharCode(c).toLowerCase();
16729 this.cleanUpPaste.defer(100, this);
16737 e.preventDefault();
16745 fixKeys : function(){ // load time branching for fastest keydown performance
16747 return function(e){
16748 var k = e.getKey(), r;
16751 r = this.doc.selection.createRange();
16754 r.pasteHTML('    ');
16761 r = this.doc.selection.createRange();
16763 var target = r.parentElement();
16764 if(!target || target.tagName.toLowerCase() != 'li'){
16766 r.pasteHTML('<br />');
16772 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16773 this.cleanUpPaste.defer(100, this);
16779 }else if(Roo.isOpera){
16780 return function(e){
16781 var k = e.getKey();
16785 this.execCmd('InsertHTML','    ');
16788 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16789 this.cleanUpPaste.defer(100, this);
16794 }else if(Roo.isSafari){
16795 return function(e){
16796 var k = e.getKey();
16800 this.execCmd('InsertText','\t');
16804 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16805 this.cleanUpPaste.defer(100, this);
16813 getAllAncestors: function()
16815 var p = this.getSelectedNode();
16818 a.push(p); // push blank onto stack..
16819 p = this.getParentElement();
16823 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16827 a.push(this.doc.body);
16831 lastSelNode : false,
16834 getSelection : function()
16836 this.assignDocWin();
16837 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16840 getSelectedNode: function()
16842 // this may only work on Gecko!!!
16844 // should we cache this!!!!
16849 var range = this.createRange(this.getSelection()).cloneRange();
16852 var parent = range.parentElement();
16854 var testRange = range.duplicate();
16855 testRange.moveToElementText(parent);
16856 if (testRange.inRange(range)) {
16859 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16862 parent = parent.parentElement;
16867 // is ancestor a text element.
16868 var ac = range.commonAncestorContainer;
16869 if (ac.nodeType == 3) {
16870 ac = ac.parentNode;
16873 var ar = ac.childNodes;
16876 var other_nodes = [];
16877 var has_other_nodes = false;
16878 for (var i=0;i<ar.length;i++) {
16879 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16882 // fullly contained node.
16884 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16889 // probably selected..
16890 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16891 other_nodes.push(ar[i]);
16895 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16900 has_other_nodes = true;
16902 if (!nodes.length && other_nodes.length) {
16903 nodes= other_nodes;
16905 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16911 createRange: function(sel)
16913 // this has strange effects when using with
16914 // top toolbar - not sure if it's a great idea.
16915 //this.editor.contentWindow.focus();
16916 if (typeof sel != "undefined") {
16918 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16920 return this.doc.createRange();
16923 return this.doc.createRange();
16926 getParentElement: function()
16929 this.assignDocWin();
16930 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16932 var range = this.createRange(sel);
16935 var p = range.commonAncestorContainer;
16936 while (p.nodeType == 3) { // text node
16947 * Range intersection.. the hard stuff...
16951 * [ -- selected range --- ]
16955 * if end is before start or hits it. fail.
16956 * if start is after end or hits it fail.
16958 * if either hits (but other is outside. - then it's not
16964 // @see http://www.thismuchiknow.co.uk/?p=64.
16965 rangeIntersectsNode : function(range, node)
16967 var nodeRange = node.ownerDocument.createRange();
16969 nodeRange.selectNode(node);
16971 nodeRange.selectNodeContents(node);
16974 var rangeStartRange = range.cloneRange();
16975 rangeStartRange.collapse(true);
16977 var rangeEndRange = range.cloneRange();
16978 rangeEndRange.collapse(false);
16980 var nodeStartRange = nodeRange.cloneRange();
16981 nodeStartRange.collapse(true);
16983 var nodeEndRange = nodeRange.cloneRange();
16984 nodeEndRange.collapse(false);
16986 return rangeStartRange.compareBoundaryPoints(
16987 Range.START_TO_START, nodeEndRange) == -1 &&
16988 rangeEndRange.compareBoundaryPoints(
16989 Range.START_TO_START, nodeStartRange) == 1;
16993 rangeCompareNode : function(range, node)
16995 var nodeRange = node.ownerDocument.createRange();
16997 nodeRange.selectNode(node);
16999 nodeRange.selectNodeContents(node);
17003 range.collapse(true);
17005 nodeRange.collapse(true);
17007 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17008 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17010 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17012 var nodeIsBefore = ss == 1;
17013 var nodeIsAfter = ee == -1;
17015 if (nodeIsBefore && nodeIsAfter)
17017 if (!nodeIsBefore && nodeIsAfter)
17018 return 1; //right trailed.
17020 if (nodeIsBefore && !nodeIsAfter)
17021 return 2; // left trailed.
17026 // private? - in a new class?
17027 cleanUpPaste : function()
17029 // cleans up the whole document..
17030 Roo.log('cleanuppaste');
17032 this.cleanUpChildren(this.doc.body);
17033 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17034 if (clean != this.doc.body.innerHTML) {
17035 this.doc.body.innerHTML = clean;
17040 cleanWordChars : function(input) {// change the chars to hex code
17041 var he = Roo.HtmlEditorCore;
17043 var output = input;
17044 Roo.each(he.swapCodes, function(sw) {
17045 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17047 output = output.replace(swapper, sw[1]);
17054 cleanUpChildren : function (n)
17056 if (!n.childNodes.length) {
17059 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17060 this.cleanUpChild(n.childNodes[i]);
17067 cleanUpChild : function (node)
17070 //console.log(node);
17071 if (node.nodeName == "#text") {
17072 // clean up silly Windows -- stuff?
17075 if (node.nodeName == "#comment") {
17076 node.parentNode.removeChild(node);
17077 // clean up silly Windows -- stuff?
17081 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17083 node.parentNode.removeChild(node);
17088 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17090 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17091 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17093 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17094 // remove_keep_children = true;
17097 if (remove_keep_children) {
17098 this.cleanUpChildren(node);
17099 // inserts everything just before this node...
17100 while (node.childNodes.length) {
17101 var cn = node.childNodes[0];
17102 node.removeChild(cn);
17103 node.parentNode.insertBefore(cn, node);
17105 node.parentNode.removeChild(node);
17109 if (!node.attributes || !node.attributes.length) {
17110 this.cleanUpChildren(node);
17114 function cleanAttr(n,v)
17117 if (v.match(/^\./) || v.match(/^\//)) {
17120 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17123 if (v.match(/^#/)) {
17126 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17127 node.removeAttribute(n);
17131 function cleanStyle(n,v)
17133 if (v.match(/expression/)) { //XSS?? should we even bother..
17134 node.removeAttribute(n);
17137 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17138 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17141 var parts = v.split(/;/);
17144 Roo.each(parts, function(p) {
17145 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17149 var l = p.split(':').shift().replace(/\s+/g,'');
17150 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17152 if ( cblack.indexOf(l) > -1) {
17153 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17154 //node.removeAttribute(n);
17158 // only allow 'c whitelisted system attributes'
17159 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17160 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17161 //node.removeAttribute(n);
17171 if (clean.length) {
17172 node.setAttribute(n, clean.join(';'));
17174 node.removeAttribute(n);
17180 for (var i = node.attributes.length-1; i > -1 ; i--) {
17181 var a = node.attributes[i];
17184 if (a.name.toLowerCase().substr(0,2)=='on') {
17185 node.removeAttribute(a.name);
17188 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17189 node.removeAttribute(a.name);
17192 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17193 cleanAttr(a.name,a.value); // fixme..
17196 if (a.name == 'style') {
17197 cleanStyle(a.name,a.value);
17200 /// clean up MS crap..
17201 // tecnically this should be a list of valid class'es..
17204 if (a.name == 'class') {
17205 if (a.value.match(/^Mso/)) {
17206 node.className = '';
17209 if (a.value.match(/body/)) {
17210 node.className = '';
17221 this.cleanUpChildren(node);
17226 * Clean up MS wordisms...
17228 cleanWord : function(node)
17231 var cleanWordChildren = function()
17233 if (!node.childNodes.length) {
17236 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17237 _t.cleanWord(node.childNodes[i]);
17243 this.cleanWord(this.doc.body);
17246 if (node.nodeName == "#text") {
17247 // clean up silly Windows -- stuff?
17250 if (node.nodeName == "#comment") {
17251 node.parentNode.removeChild(node);
17252 // clean up silly Windows -- stuff?
17256 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17257 node.parentNode.removeChild(node);
17261 // remove - but keep children..
17262 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17263 while (node.childNodes.length) {
17264 var cn = node.childNodes[0];
17265 node.removeChild(cn);
17266 node.parentNode.insertBefore(cn, node);
17268 node.parentNode.removeChild(node);
17269 cleanWordChildren();
17273 if (node.className.length) {
17275 var cn = node.className.split(/\W+/);
17277 Roo.each(cn, function(cls) {
17278 if (cls.match(/Mso[a-zA-Z]+/)) {
17283 node.className = cna.length ? cna.join(' ') : '';
17285 node.removeAttribute("class");
17289 if (node.hasAttribute("lang")) {
17290 node.removeAttribute("lang");
17293 if (node.hasAttribute("style")) {
17295 var styles = node.getAttribute("style").split(";");
17297 Roo.each(styles, function(s) {
17298 if (!s.match(/:/)) {
17301 var kv = s.split(":");
17302 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17305 // what ever is left... we allow.
17308 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17309 if (!nstyle.length) {
17310 node.removeAttribute('style');
17314 cleanWordChildren();
17318 domToHTML : function(currentElement, depth, nopadtext) {
17320 depth = depth || 0;
17321 nopadtext = nopadtext || false;
17323 if (!currentElement) {
17324 return this.domToHTML(this.doc.body);
17327 //Roo.log(currentElement);
17329 var allText = false;
17330 var nodeName = currentElement.nodeName;
17331 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17333 if (nodeName == '#text') {
17334 return currentElement.nodeValue;
17339 if (nodeName != 'BODY') {
17342 // Prints the node tagName, such as <A>, <IMG>, etc
17345 for(i = 0; i < currentElement.attributes.length;i++) {
17347 var aname = currentElement.attributes.item(i).name;
17348 if (!currentElement.attributes.item(i).value.length) {
17351 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17354 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17363 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17366 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17371 // Traverse the tree
17373 var currentElementChild = currentElement.childNodes.item(i);
17374 var allText = true;
17375 var innerHTML = '';
17377 while (currentElementChild) {
17378 // Formatting code (indent the tree so it looks nice on the screen)
17379 var nopad = nopadtext;
17380 if (lastnode == 'SPAN') {
17384 if (currentElementChild.nodeName == '#text') {
17385 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17386 if (!nopad && toadd.length > 80) {
17387 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17389 innerHTML += toadd;
17392 currentElementChild = currentElement.childNodes.item(i);
17398 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17400 // Recursively traverse the tree structure of the child node
17401 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17402 lastnode = currentElementChild.nodeName;
17404 currentElementChild=currentElement.childNodes.item(i);
17410 // The remaining code is mostly for formatting the tree
17411 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17416 ret+= "</"+tagName+">";
17422 // hide stuff that is not compatible
17436 * @event specialkey
17440 * @cfg {String} fieldClass @hide
17443 * @cfg {String} focusClass @hide
17446 * @cfg {String} autoCreate @hide
17449 * @cfg {String} inputType @hide
17452 * @cfg {String} invalidClass @hide
17455 * @cfg {String} invalidText @hide
17458 * @cfg {String} msgFx @hide
17461 * @cfg {String} validateOnBlur @hide
17465 Roo.HtmlEditorCore.white = [
17466 'area', 'br', 'img', 'input', 'hr', 'wbr',
17468 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17469 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17470 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17471 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17472 'table', 'ul', 'xmp',
17474 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17477 'dir', 'menu', 'ol', 'ul', 'dl',
17483 Roo.HtmlEditorCore.black = [
17484 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17486 'base', 'basefont', 'bgsound', 'blink', 'body',
17487 'frame', 'frameset', 'head', 'html', 'ilayer',
17488 'iframe', 'layer', 'link', 'meta', 'object',
17489 'script', 'style' ,'title', 'xml' // clean later..
17491 Roo.HtmlEditorCore.clean = [
17492 'script', 'style', 'title', 'xml'
17494 Roo.HtmlEditorCore.remove = [
17499 Roo.HtmlEditorCore.ablack = [
17503 Roo.HtmlEditorCore.aclean = [
17504 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17508 Roo.HtmlEditorCore.pwhite= [
17509 'http', 'https', 'mailto'
17512 // white listed style attributes.
17513 Roo.HtmlEditorCore.cwhite= [
17514 // 'text-align', /// default is to allow most things..
17520 // black listed style attributes.
17521 Roo.HtmlEditorCore.cblack= [
17522 // 'font-size' -- this can be set by the project
17526 Roo.HtmlEditorCore.swapCodes =[
17545 * @class Roo.bootstrap.HtmlEditor
17546 * @extends Roo.bootstrap.TextArea
17547 * Bootstrap HtmlEditor class
17550 * Create a new HtmlEditor
17551 * @param {Object} config The config object
17554 Roo.bootstrap.HtmlEditor = function(config){
17555 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17556 if (!this.toolbars) {
17557 this.toolbars = [];
17559 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17562 * @event initialize
17563 * Fires when the editor is fully initialized (including the iframe)
17564 * @param {HtmlEditor} this
17569 * Fires when the editor is first receives the focus. Any insertion must wait
17570 * until after this event.
17571 * @param {HtmlEditor} this
17575 * @event beforesync
17576 * Fires before the textarea is updated with content from the editor iframe. Return false
17577 * to cancel the sync.
17578 * @param {HtmlEditor} this
17579 * @param {String} html
17583 * @event beforepush
17584 * Fires before the iframe editor is updated with content from the textarea. Return false
17585 * to cancel the push.
17586 * @param {HtmlEditor} this
17587 * @param {String} html
17592 * Fires when the textarea is updated with content from the editor iframe.
17593 * @param {HtmlEditor} this
17594 * @param {String} html
17599 * Fires when the iframe editor is updated with content from the textarea.
17600 * @param {HtmlEditor} this
17601 * @param {String} html
17605 * @event editmodechange
17606 * Fires when the editor switches edit modes
17607 * @param {HtmlEditor} this
17608 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17610 editmodechange: true,
17612 * @event editorevent
17613 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17614 * @param {HtmlEditor} this
17618 * @event firstfocus
17619 * Fires when on first focus - needed by toolbars..
17620 * @param {HtmlEditor} this
17625 * Auto save the htmlEditor value as a file into Events
17626 * @param {HtmlEditor} this
17630 * @event savedpreview
17631 * preview the saved version of htmlEditor
17632 * @param {HtmlEditor} this
17639 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17643 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17648 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17653 * @cfg {Number} height (in pixels)
17657 * @cfg {Number} width (in pixels)
17662 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17665 stylesheets: false,
17670 // private properties
17671 validationEvent : false,
17673 initialized : false,
17676 onFocus : Roo.emptyFn,
17678 hideMode:'offsets',
17681 tbContainer : false,
17683 toolbarContainer :function() {
17684 return this.wrap.select('.x-html-editor-tb',true).first();
17688 * Protected method that will not generally be called directly. It
17689 * is called when the editor creates its toolbar. Override this method if you need to
17690 * add custom toolbar buttons.
17691 * @param {HtmlEditor} editor
17693 createToolbar : function(){
17695 Roo.log("create toolbars");
17697 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17698 this.toolbars[0].render(this.toolbarContainer());
17702 // if (!editor.toolbars || !editor.toolbars.length) {
17703 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17706 // for (var i =0 ; i < editor.toolbars.length;i++) {
17707 // editor.toolbars[i] = Roo.factory(
17708 // typeof(editor.toolbars[i]) == 'string' ?
17709 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17710 // Roo.bootstrap.HtmlEditor);
17711 // editor.toolbars[i].init(editor);
17717 onRender : function(ct, position)
17719 // Roo.log("Call onRender: " + this.xtype);
17721 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17723 this.wrap = this.inputEl().wrap({
17724 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17727 this.editorcore.onRender(ct, position);
17729 if (this.resizable) {
17730 this.resizeEl = new Roo.Resizable(this.wrap, {
17734 minHeight : this.height,
17735 height: this.height,
17736 handles : this.resizable,
17739 resize : function(r, w, h) {
17740 _t.onResize(w,h); // -something
17746 this.createToolbar(this);
17749 if(!this.width && this.resizable){
17750 this.setSize(this.wrap.getSize());
17752 if (this.resizeEl) {
17753 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17754 // should trigger onReize..
17760 onResize : function(w, h)
17762 Roo.log('resize: ' +w + ',' + h );
17763 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17767 if(this.inputEl() ){
17768 if(typeof w == 'number'){
17769 var aw = w - this.wrap.getFrameWidth('lr');
17770 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17773 if(typeof h == 'number'){
17774 var tbh = -11; // fixme it needs to tool bar size!
17775 for (var i =0; i < this.toolbars.length;i++) {
17776 // fixme - ask toolbars for heights?
17777 tbh += this.toolbars[i].el.getHeight();
17778 //if (this.toolbars[i].footer) {
17779 // tbh += this.toolbars[i].footer.el.getHeight();
17787 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17788 ah -= 5; // knock a few pixes off for look..
17789 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17793 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17794 this.editorcore.onResize(ew,eh);
17799 * Toggles the editor between standard and source edit mode.
17800 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17802 toggleSourceEdit : function(sourceEditMode)
17804 this.editorcore.toggleSourceEdit(sourceEditMode);
17806 if(this.editorcore.sourceEditMode){
17807 Roo.log('editor - showing textarea');
17810 // Roo.log(this.syncValue());
17812 this.inputEl().removeClass(['hide', 'x-hidden']);
17813 this.inputEl().dom.removeAttribute('tabIndex');
17814 this.inputEl().focus();
17816 Roo.log('editor - hiding textarea');
17818 // Roo.log(this.pushValue());
17821 this.inputEl().addClass(['hide', 'x-hidden']);
17822 this.inputEl().dom.setAttribute('tabIndex', -1);
17823 //this.deferFocus();
17826 if(this.resizable){
17827 this.setSize(this.wrap.getSize());
17830 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17833 // private (for BoxComponent)
17834 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17836 // private (for BoxComponent)
17837 getResizeEl : function(){
17841 // private (for BoxComponent)
17842 getPositionEl : function(){
17847 initEvents : function(){
17848 this.originalValue = this.getValue();
17852 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17855 // markInvalid : Roo.emptyFn,
17857 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17860 // clearInvalid : Roo.emptyFn,
17862 setValue : function(v){
17863 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17864 this.editorcore.pushValue();
17869 deferFocus : function(){
17870 this.focus.defer(10, this);
17874 focus : function(){
17875 this.editorcore.focus();
17881 onDestroy : function(){
17887 for (var i =0; i < this.toolbars.length;i++) {
17888 // fixme - ask toolbars for heights?
17889 this.toolbars[i].onDestroy();
17892 this.wrap.dom.innerHTML = '';
17893 this.wrap.remove();
17898 onFirstFocus : function(){
17899 //Roo.log("onFirstFocus");
17900 this.editorcore.onFirstFocus();
17901 for (var i =0; i < this.toolbars.length;i++) {
17902 this.toolbars[i].onFirstFocus();
17908 syncValue : function()
17910 this.editorcore.syncValue();
17913 pushValue : function()
17915 this.editorcore.pushValue();
17919 // hide stuff that is not compatible
17933 * @event specialkey
17937 * @cfg {String} fieldClass @hide
17940 * @cfg {String} focusClass @hide
17943 * @cfg {String} autoCreate @hide
17946 * @cfg {String} inputType @hide
17949 * @cfg {String} invalidClass @hide
17952 * @cfg {String} invalidText @hide
17955 * @cfg {String} msgFx @hide
17958 * @cfg {String} validateOnBlur @hide
17967 Roo.namespace('Roo.bootstrap.htmleditor');
17969 * @class Roo.bootstrap.HtmlEditorToolbar1
17974 new Roo.bootstrap.HtmlEditor({
17977 new Roo.bootstrap.HtmlEditorToolbar1({
17978 disable : { fonts: 1 , format: 1, ..., ... , ...],
17984 * @cfg {Object} disable List of elements to disable..
17985 * @cfg {Array} btns List of additional buttons.
17989 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17992 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17995 Roo.apply(this, config);
17997 // default disabled, based on 'good practice'..
17998 this.disable = this.disable || {};
17999 Roo.applyIf(this.disable, {
18002 specialElements : true
18004 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18006 this.editor = config.editor;
18007 this.editorcore = config.editor.editorcore;
18009 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18011 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18012 // dont call parent... till later.
18014 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18019 editorcore : false,
18024 "h1","h2","h3","h4","h5","h6",
18026 "abbr", "acronym", "address", "cite", "samp", "var",
18030 onRender : function(ct, position)
18032 // Roo.log("Call onRender: " + this.xtype);
18034 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18036 this.el.dom.style.marginBottom = '0';
18038 var editorcore = this.editorcore;
18039 var editor= this.editor;
18042 var btn = function(id,cmd , toggle, handler){
18044 var event = toggle ? 'toggle' : 'click';
18049 xns: Roo.bootstrap,
18052 enableToggle:toggle !== false,
18054 pressed : toggle ? false : null,
18057 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18058 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18067 xns: Roo.bootstrap,
18068 glyphicon : 'font',
18072 xns: Roo.bootstrap,
18076 Roo.each(this.formats, function(f) {
18077 style.menu.items.push({
18079 xns: Roo.bootstrap,
18080 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18085 editorcore.insertTag(this.tagname);
18092 children.push(style);
18095 btn('bold',false,true);
18096 btn('italic',false,true);
18097 btn('align-left', 'justifyleft',true);
18098 btn('align-center', 'justifycenter',true);
18099 btn('align-right' , 'justifyright',true);
18100 btn('link', false, false, function(btn) {
18101 //Roo.log("create link?");
18102 var url = prompt(this.createLinkText, this.defaultLinkValue);
18103 if(url && url != 'http:/'+'/'){
18104 this.editorcore.relayCmd('createlink', url);
18107 btn('list','insertunorderedlist',true);
18108 btn('pencil', false,true, function(btn){
18111 this.toggleSourceEdit(btn.pressed);
18117 xns: Roo.bootstrap,
18122 xns: Roo.bootstrap,
18127 cog.menu.items.push({
18129 xns: Roo.bootstrap,
18130 html : Clean styles,
18135 editorcore.insertTag(this.tagname);
18144 this.xtype = 'NavSimplebar';
18146 for(var i=0;i< children.length;i++) {
18148 this.buttons.add(this.addxtypeChild(children[i]));
18152 editor.on('editorevent', this.updateToolbar, this);
18154 onBtnClick : function(id)
18156 this.editorcore.relayCmd(id);
18157 this.editorcore.focus();
18161 * Protected method that will not generally be called directly. It triggers
18162 * a toolbar update by reading the markup state of the current selection in the editor.
18164 updateToolbar: function(){
18166 if(!this.editorcore.activated){
18167 this.editor.onFirstFocus(); // is this neeed?
18171 var btns = this.buttons;
18172 var doc = this.editorcore.doc;
18173 btns.get('bold').setActive(doc.queryCommandState('bold'));
18174 btns.get('italic').setActive(doc.queryCommandState('italic'));
18175 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18177 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18178 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18179 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18181 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18182 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18185 var ans = this.editorcore.getAllAncestors();
18186 if (this.formatCombo) {
18189 var store = this.formatCombo.store;
18190 this.formatCombo.setValue("");
18191 for (var i =0; i < ans.length;i++) {
18192 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18194 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18202 // hides menus... - so this cant be on a menu...
18203 Roo.bootstrap.MenuMgr.hideAll();
18205 Roo.bootstrap.MenuMgr.hideAll();
18206 //this.editorsyncValue();
18208 onFirstFocus: function() {
18209 this.buttons.each(function(item){
18213 toggleSourceEdit : function(sourceEditMode){
18216 if(sourceEditMode){
18217 Roo.log("disabling buttons");
18218 this.buttons.each( function(item){
18219 if(item.cmd != 'pencil'){
18225 Roo.log("enabling buttons");
18226 if(this.editorcore.initialized){
18227 this.buttons.each( function(item){
18233 Roo.log("calling toggole on editor");
18234 // tell the editor that it's been pressed..
18235 this.editor.toggleSourceEdit(sourceEditMode);
18245 * @class Roo.bootstrap.Table.AbstractSelectionModel
18246 * @extends Roo.util.Observable
18247 * Abstract base class for grid SelectionModels. It provides the interface that should be
18248 * implemented by descendant classes. This class should not be directly instantiated.
18251 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18252 this.locked = false;
18253 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18257 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18258 /** @ignore Called by the grid automatically. Do not call directly. */
18259 init : function(grid){
18265 * Locks the selections.
18268 this.locked = true;
18272 * Unlocks the selections.
18274 unlock : function(){
18275 this.locked = false;
18279 * Returns true if the selections are locked.
18280 * @return {Boolean}
18282 isLocked : function(){
18283 return this.locked;
18287 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18288 * @class Roo.bootstrap.Table.RowSelectionModel
18289 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18290 * It supports multiple selections and keyboard selection/navigation.
18292 * @param {Object} config
18295 Roo.bootstrap.Table.RowSelectionModel = function(config){
18296 Roo.apply(this, config);
18297 this.selections = new Roo.util.MixedCollection(false, function(o){
18302 this.lastActive = false;
18306 * @event selectionchange
18307 * Fires when the selection changes
18308 * @param {SelectionModel} this
18310 "selectionchange" : true,
18312 * @event afterselectionchange
18313 * Fires after the selection changes (eg. by key press or clicking)
18314 * @param {SelectionModel} this
18316 "afterselectionchange" : true,
18318 * @event beforerowselect
18319 * Fires when a row is selected being selected, return false to cancel.
18320 * @param {SelectionModel} this
18321 * @param {Number} rowIndex The selected index
18322 * @param {Boolean} keepExisting False if other selections will be cleared
18324 "beforerowselect" : true,
18327 * Fires when a row is selected.
18328 * @param {SelectionModel} this
18329 * @param {Number} rowIndex The selected index
18330 * @param {Roo.data.Record} r The record
18332 "rowselect" : true,
18334 * @event rowdeselect
18335 * Fires when a row is deselected.
18336 * @param {SelectionModel} this
18337 * @param {Number} rowIndex The selected index
18339 "rowdeselect" : true
18341 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18342 this.locked = false;
18345 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18347 * @cfg {Boolean} singleSelect
18348 * True to allow selection of only one row at a time (defaults to false)
18350 singleSelect : false,
18353 initEvents : function(){
18355 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18356 this.grid.on("mousedown", this.handleMouseDown, this);
18357 }else{ // allow click to work like normal
18358 this.grid.on("rowclick", this.handleDragableRowClick, this);
18361 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18362 "up" : function(e){
18364 this.selectPrevious(e.shiftKey);
18365 }else if(this.last !== false && this.lastActive !== false){
18366 var last = this.last;
18367 this.selectRange(this.last, this.lastActive-1);
18368 this.grid.getView().focusRow(this.lastActive);
18369 if(last !== false){
18373 this.selectFirstRow();
18375 this.fireEvent("afterselectionchange", this);
18377 "down" : function(e){
18379 this.selectNext(e.shiftKey);
18380 }else if(this.last !== false && this.lastActive !== false){
18381 var last = this.last;
18382 this.selectRange(this.last, this.lastActive+1);
18383 this.grid.getView().focusRow(this.lastActive);
18384 if(last !== false){
18388 this.selectFirstRow();
18390 this.fireEvent("afterselectionchange", this);
18395 var view = this.grid.view;
18396 view.on("refresh", this.onRefresh, this);
18397 view.on("rowupdated", this.onRowUpdated, this);
18398 view.on("rowremoved", this.onRemove, this);
18402 onRefresh : function(){
18403 var ds = this.grid.dataSource, i, v = this.grid.view;
18404 var s = this.selections;
18405 s.each(function(r){
18406 if((i = ds.indexOfId(r.id)) != -1){
18415 onRemove : function(v, index, r){
18416 this.selections.remove(r);
18420 onRowUpdated : function(v, index, r){
18421 if(this.isSelected(r)){
18422 v.onRowSelect(index);
18428 * @param {Array} records The records to select
18429 * @param {Boolean} keepExisting (optional) True to keep existing selections
18431 selectRecords : function(records, keepExisting){
18433 this.clearSelections();
18435 var ds = this.grid.dataSource;
18436 for(var i = 0, len = records.length; i < len; i++){
18437 this.selectRow(ds.indexOf(records[i]), true);
18442 * Gets the number of selected rows.
18445 getCount : function(){
18446 return this.selections.length;
18450 * Selects the first row in the grid.
18452 selectFirstRow : function(){
18457 * Select the last row.
18458 * @param {Boolean} keepExisting (optional) True to keep existing selections
18460 selectLastRow : function(keepExisting){
18461 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18465 * Selects the row immediately following the last selected row.
18466 * @param {Boolean} keepExisting (optional) True to keep existing selections
18468 selectNext : function(keepExisting){
18469 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18470 this.selectRow(this.last+1, keepExisting);
18471 this.grid.getView().focusRow(this.last);
18476 * Selects the row that precedes the last selected row.
18477 * @param {Boolean} keepExisting (optional) True to keep existing selections
18479 selectPrevious : function(keepExisting){
18481 this.selectRow(this.last-1, keepExisting);
18482 this.grid.getView().focusRow(this.last);
18487 * Returns the selected records
18488 * @return {Array} Array of selected records
18490 getSelections : function(){
18491 return [].concat(this.selections.items);
18495 * Returns the first selected record.
18498 getSelected : function(){
18499 return this.selections.itemAt(0);
18504 * Clears all selections.
18506 clearSelections : function(fast){
18507 if(this.locked) return;
18509 var ds = this.grid.dataSource;
18510 var s = this.selections;
18511 s.each(function(r){
18512 this.deselectRow(ds.indexOfId(r.id));
18516 this.selections.clear();
18523 * Selects all rows.
18525 selectAll : function(){
18526 if(this.locked) return;
18527 this.selections.clear();
18528 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18529 this.selectRow(i, true);
18534 * Returns True if there is a selection.
18535 * @return {Boolean}
18537 hasSelection : function(){
18538 return this.selections.length > 0;
18542 * Returns True if the specified row is selected.
18543 * @param {Number/Record} record The record or index of the record to check
18544 * @return {Boolean}
18546 isSelected : function(index){
18547 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18548 return (r && this.selections.key(r.id) ? true : false);
18552 * Returns True if the specified record id is selected.
18553 * @param {String} id The id of record to check
18554 * @return {Boolean}
18556 isIdSelected : function(id){
18557 return (this.selections.key(id) ? true : false);
18561 handleMouseDown : function(e, t){
18562 var view = this.grid.getView(), rowIndex;
18563 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18566 if(e.shiftKey && this.last !== false){
18567 var last = this.last;
18568 this.selectRange(last, rowIndex, e.ctrlKey);
18569 this.last = last; // reset the last
18570 view.focusRow(rowIndex);
18572 var isSelected = this.isSelected(rowIndex);
18573 if(e.button !== 0 && isSelected){
18574 view.focusRow(rowIndex);
18575 }else if(e.ctrlKey && isSelected){
18576 this.deselectRow(rowIndex);
18577 }else if(!isSelected){
18578 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18579 view.focusRow(rowIndex);
18582 this.fireEvent("afterselectionchange", this);
18585 handleDragableRowClick : function(grid, rowIndex, e)
18587 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18588 this.selectRow(rowIndex, false);
18589 grid.view.focusRow(rowIndex);
18590 this.fireEvent("afterselectionchange", this);
18595 * Selects multiple rows.
18596 * @param {Array} rows Array of the indexes of the row to select
18597 * @param {Boolean} keepExisting (optional) True to keep existing selections
18599 selectRows : function(rows, keepExisting){
18601 this.clearSelections();
18603 for(var i = 0, len = rows.length; i < len; i++){
18604 this.selectRow(rows[i], true);
18609 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18610 * @param {Number} startRow The index of the first row in the range
18611 * @param {Number} endRow The index of the last row in the range
18612 * @param {Boolean} keepExisting (optional) True to retain existing selections
18614 selectRange : function(startRow, endRow, keepExisting){
18615 if(this.locked) return;
18617 this.clearSelections();
18619 if(startRow <= endRow){
18620 for(var i = startRow; i <= endRow; i++){
18621 this.selectRow(i, true);
18624 for(var i = startRow; i >= endRow; i--){
18625 this.selectRow(i, true);
18631 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18632 * @param {Number} startRow The index of the first row in the range
18633 * @param {Number} endRow The index of the last row in the range
18635 deselectRange : function(startRow, endRow, preventViewNotify){
18636 if(this.locked) return;
18637 for(var i = startRow; i <= endRow; i++){
18638 this.deselectRow(i, preventViewNotify);
18644 * @param {Number} row The index of the row to select
18645 * @param {Boolean} keepExisting (optional) True to keep existing selections
18647 selectRow : function(index, keepExisting, preventViewNotify){
18648 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18649 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18650 if(!keepExisting || this.singleSelect){
18651 this.clearSelections();
18653 var r = this.grid.dataSource.getAt(index);
18654 this.selections.add(r);
18655 this.last = this.lastActive = index;
18656 if(!preventViewNotify){
18657 this.grid.getView().onRowSelect(index);
18659 this.fireEvent("rowselect", this, index, r);
18660 this.fireEvent("selectionchange", this);
18666 * @param {Number} row The index of the row to deselect
18668 deselectRow : function(index, preventViewNotify){
18669 if(this.locked) return;
18670 if(this.last == index){
18673 if(this.lastActive == index){
18674 this.lastActive = false;
18676 var r = this.grid.dataSource.getAt(index);
18677 this.selections.remove(r);
18678 if(!preventViewNotify){
18679 this.grid.getView().onRowDeselect(index);
18681 this.fireEvent("rowdeselect", this, index);
18682 this.fireEvent("selectionchange", this);
18686 restoreLast : function(){
18688 this.last = this._last;
18693 acceptsNav : function(row, col, cm){
18694 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18698 onEditorKey : function(field, e){
18699 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18704 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18706 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18708 }else if(k == e.ENTER && !e.ctrlKey){
18712 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18714 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18716 }else if(k == e.ESC){
18720 g.startEditing(newCell[0], newCell[1]);
18725 * Ext JS Library 1.1.1
18726 * Copyright(c) 2006-2007, Ext JS, LLC.
18728 * Originally Released Under LGPL - original licence link has changed is not relivant.
18731 * <script type="text/javascript">
18735 * @class Roo.bootstrap.PagingToolbar
18737 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18739 * Create a new PagingToolbar
18740 * @param {Object} config The config object
18742 Roo.bootstrap.PagingToolbar = function(config)
18744 // old args format still supported... - xtype is prefered..
18745 // created from xtype...
18746 var ds = config.dataSource;
18747 this.toolbarItems = [];
18748 if (config.items) {
18749 this.toolbarItems = config.items;
18750 // config.items = [];
18753 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18760 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18764 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18766 * @cfg {Roo.data.Store} dataSource
18767 * The underlying data store providing the paged data
18770 * @cfg {String/HTMLElement/Element} container
18771 * container The id or element that will contain the toolbar
18774 * @cfg {Boolean} displayInfo
18775 * True to display the displayMsg (defaults to false)
18778 * @cfg {Number} pageSize
18779 * The number of records to display per page (defaults to 20)
18783 * @cfg {String} displayMsg
18784 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18786 displayMsg : 'Displaying {0} - {1} of {2}',
18788 * @cfg {String} emptyMsg
18789 * The message to display when no records are found (defaults to "No data to display")
18791 emptyMsg : 'No data to display',
18793 * Customizable piece of the default paging text (defaults to "Page")
18796 beforePageText : "Page",
18798 * Customizable piece of the default paging text (defaults to "of %0")
18801 afterPageText : "of {0}",
18803 * Customizable piece of the default paging text (defaults to "First Page")
18806 firstText : "First Page",
18808 * Customizable piece of the default paging text (defaults to "Previous Page")
18811 prevText : "Previous Page",
18813 * Customizable piece of the default paging text (defaults to "Next Page")
18816 nextText : "Next Page",
18818 * Customizable piece of the default paging text (defaults to "Last Page")
18821 lastText : "Last Page",
18823 * Customizable piece of the default paging text (defaults to "Refresh")
18826 refreshText : "Refresh",
18830 onRender : function(ct, position)
18832 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18833 this.navgroup.parentId = this.id;
18834 this.navgroup.onRender(this.el, null);
18835 // add the buttons to the navgroup
18837 if(this.displayInfo){
18838 Roo.log(this.el.select('ul.navbar-nav',true).first());
18839 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18840 this.displayEl = this.el.select('.x-paging-info', true).first();
18841 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18842 // this.displayEl = navel.el.select('span',true).first();
18848 Roo.each(_this.buttons, function(e){
18849 Roo.factory(e).onRender(_this.el, null);
18853 Roo.each(_this.toolbarItems, function(e) {
18854 _this.navgroup.addItem(e);
18857 this.first = this.navgroup.addItem({
18858 tooltip: this.firstText,
18860 icon : 'fa fa-backward',
18862 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18865 this.prev = this.navgroup.addItem({
18866 tooltip: this.prevText,
18868 icon : 'fa fa-step-backward',
18870 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18872 //this.addSeparator();
18875 var field = this.navgroup.addItem( {
18877 cls : 'x-paging-position',
18879 html : this.beforePageText +
18880 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18881 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18884 this.field = field.el.select('input', true).first();
18885 this.field.on("keydown", this.onPagingKeydown, this);
18886 this.field.on("focus", function(){this.dom.select();});
18889 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18890 //this.field.setHeight(18);
18891 //this.addSeparator();
18892 this.next = this.navgroup.addItem({
18893 tooltip: this.nextText,
18895 html : ' <i class="fa fa-step-forward">',
18897 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18899 this.last = this.navgroup.addItem({
18900 tooltip: this.lastText,
18901 icon : 'fa fa-forward',
18904 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18906 //this.addSeparator();
18907 this.loading = this.navgroup.addItem({
18908 tooltip: this.refreshText,
18909 icon: 'fa fa-refresh',
18911 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18917 updateInfo : function(){
18918 if(this.displayEl){
18919 var count = this.ds.getCount();
18920 var msg = count == 0 ?
18924 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18926 this.displayEl.update(msg);
18931 onLoad : function(ds, r, o){
18932 this.cursor = o.params ? o.params.start : 0;
18933 var d = this.getPageData(),
18937 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18938 this.field.dom.value = ap;
18939 this.first.setDisabled(ap == 1);
18940 this.prev.setDisabled(ap == 1);
18941 this.next.setDisabled(ap == ps);
18942 this.last.setDisabled(ap == ps);
18943 this.loading.enable();
18948 getPageData : function(){
18949 var total = this.ds.getTotalCount();
18952 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18953 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18958 onLoadError : function(){
18959 this.loading.enable();
18963 onPagingKeydown : function(e){
18964 var k = e.getKey();
18965 var d = this.getPageData();
18967 var v = this.field.dom.value, pageNum;
18968 if(!v || isNaN(pageNum = parseInt(v, 10))){
18969 this.field.dom.value = d.activePage;
18972 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18973 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18976 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))
18978 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18979 this.field.dom.value = pageNum;
18980 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18983 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18985 var v = this.field.dom.value, pageNum;
18986 var increment = (e.shiftKey) ? 10 : 1;
18987 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18989 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18990 this.field.dom.value = d.activePage;
18993 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18995 this.field.dom.value = parseInt(v, 10) + increment;
18996 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18997 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19004 beforeLoad : function(){
19006 this.loading.disable();
19011 onClick : function(which){
19018 ds.load({params:{start: 0, limit: this.pageSize}});
19021 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19024 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19027 var total = ds.getTotalCount();
19028 var extra = total % this.pageSize;
19029 var lastStart = extra ? (total - extra) : total-this.pageSize;
19030 ds.load({params:{start: lastStart, limit: this.pageSize}});
19033 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19039 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19040 * @param {Roo.data.Store} store The data store to unbind
19042 unbind : function(ds){
19043 ds.un("beforeload", this.beforeLoad, this);
19044 ds.un("load", this.onLoad, this);
19045 ds.un("loadexception", this.onLoadError, this);
19046 ds.un("remove", this.updateInfo, this);
19047 ds.un("add", this.updateInfo, this);
19048 this.ds = undefined;
19052 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19053 * @param {Roo.data.Store} store The data store to bind
19055 bind : function(ds){
19056 ds.on("beforeload", this.beforeLoad, this);
19057 ds.on("load", this.onLoad, this);
19058 ds.on("loadexception", this.onLoadError, this);
19059 ds.on("remove", this.updateInfo, this);
19060 ds.on("add", this.updateInfo, this);
19071 * @class Roo.bootstrap.MessageBar
19072 * @extends Roo.bootstrap.Component
19073 * Bootstrap MessageBar class
19074 * @cfg {String} html contents of the MessageBar
19075 * @cfg {String} weight (info | success | warning | danger) default info
19076 * @cfg {String} beforeClass insert the bar before the given class
19077 * @cfg {Boolean} closable (true | false) default false
19078 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19081 * Create a new Element
19082 * @param {Object} config The config object
19085 Roo.bootstrap.MessageBar = function(config){
19086 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19089 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19095 beforeClass: 'bootstrap-sticky-wrap',
19097 getAutoCreate : function(){
19101 cls: 'alert alert-dismissable alert-' + this.weight,
19106 html: this.html || ''
19112 cfg.cls += ' alert-messages-fixed';
19126 onRender : function(ct, position)
19128 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19131 var cfg = Roo.apply({}, this.getAutoCreate());
19135 cfg.cls += ' ' + this.cls;
19138 cfg.style = this.style;
19140 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19142 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19145 this.el.select('>button.close').on('click', this.hide, this);
19151 if (!this.rendered) {
19157 this.fireEvent('show', this);
19163 if (!this.rendered) {
19169 this.fireEvent('hide', this);
19172 update : function()
19174 // var e = this.el.dom.firstChild;
19176 // if(this.closable){
19177 // e = e.nextSibling;
19180 // e.data = this.html || '';
19182 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19198 * @class Roo.bootstrap.Graph
19199 * @extends Roo.bootstrap.Component
19200 * Bootstrap Graph class
19204 @cfg {String} graphtype bar | vbar | pie
19205 @cfg {number} g_x coodinator | centre x (pie)
19206 @cfg {number} g_y coodinator | centre y (pie)
19207 @cfg {number} g_r radius (pie)
19208 @cfg {number} g_height height of the chart (respected by all elements in the set)
19209 @cfg {number} g_width width of the chart (respected by all elements in the set)
19210 @cfg {Object} title The title of the chart
19213 -opts (object) options for the chart
19215 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19216 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19218 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.
19219 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19221 o stretch (boolean)
19223 -opts (object) options for the pie
19226 o startAngle (number)
19227 o endAngle (number)
19231 * Create a new Input
19232 * @param {Object} config The config object
19235 Roo.bootstrap.Graph = function(config){
19236 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19242 * The img click event for the img.
19243 * @param {Roo.EventObject} e
19249 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19260 //g_colors: this.colors,
19267 getAutoCreate : function(){
19278 onRender : function(ct,position){
19279 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19280 this.raphael = Raphael(this.el.dom);
19282 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19283 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19284 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19285 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19287 r.text(160, 10, "Single Series Chart").attr(txtattr);
19288 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19289 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19290 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19292 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19293 r.barchart(330, 10, 300, 220, data1);
19294 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19295 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19298 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19299 // r.barchart(30, 30, 560, 250, xdata, {
19300 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19301 // axis : "0 0 1 1",
19302 // axisxlabels : xdata
19303 // //yvalues : cols,
19306 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19308 // this.load(null,xdata,{
19309 // axis : "0 0 1 1",
19310 // axisxlabels : xdata
19315 load : function(graphtype,xdata,opts){
19316 this.raphael.clear();
19318 graphtype = this.graphtype;
19323 var r = this.raphael,
19324 fin = function () {
19325 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19327 fout = function () {
19328 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19330 pfin = function() {
19331 this.sector.stop();
19332 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19335 this.label[0].stop();
19336 this.label[0].attr({ r: 7.5 });
19337 this.label[1].attr({ "font-weight": 800 });
19340 pfout = function() {
19341 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19344 this.label[0].animate({ r: 5 }, 500, "bounce");
19345 this.label[1].attr({ "font-weight": 400 });
19351 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19354 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19357 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19358 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19360 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19367 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19372 setTitle: function(o)
19377 initEvents: function() {
19380 this.el.on('click', this.onClick, this);
19384 onClick : function(e)
19386 Roo.log('img onclick');
19387 this.fireEvent('click', this, e);
19399 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19402 * @class Roo.bootstrap.dash.NumberBox
19403 * @extends Roo.bootstrap.Component
19404 * Bootstrap NumberBox class
19405 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19406 * @cfg {String} headline Box headline
19407 * @cfg {String} content Box content
19408 * @cfg {String} icon Box icon
19409 * @cfg {String} footer Footer text
19410 * @cfg {String} fhref Footer href
19413 * Create a new NumberBox
19414 * @param {Object} config The config object
19418 Roo.bootstrap.dash.NumberBox = function(config){
19419 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19423 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19433 getAutoCreate : function(){
19437 cls : 'small-box bg-' + this.bgcolor,
19445 cls : 'roo-headline',
19446 html : this.headline
19450 cls : 'roo-content',
19451 html : this.content
19465 cls : 'ion ' + this.icon
19474 cls : 'small-box-footer',
19475 href : this.fhref || '#',
19479 cfg.cn.push(footer);
19486 onRender : function(ct,position){
19487 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19494 setHeadline: function (value)
19496 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19499 setFooter: function (value, href)
19501 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19504 this.el.select('a.small-box-footer',true).first().attr('href', href);
19509 setContent: function (value)
19511 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19514 initEvents: function()
19528 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19531 * @class Roo.bootstrap.dash.TabBox
19532 * @extends Roo.bootstrap.Component
19533 * Bootstrap TabBox class
19534 * @cfg {String} title Title of the TabBox
19535 * @cfg {String} icon Icon of the TabBox
19538 * Create a new TabBox
19539 * @param {Object} config The config object
19543 Roo.bootstrap.dash.TabBox = function(config){
19544 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19549 * When a pane is added
19550 * @param {Roo.bootstrap.dash.TabPane} pane
19557 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19562 getChildContainer : function()
19564 return this.el.select('.tab-content', true).first();
19567 getAutoCreate : function(){
19571 cls: 'pull-left header',
19579 cls: 'fa ' + this.icon
19586 cls: 'nav-tabs-custom',
19590 cls: 'nav nav-tabs pull-right',
19597 cls: 'tab-content no-padding',
19605 initEvents : function()
19607 //Roo.log('add add pane handler');
19608 this.on('addpane', this.onAddPane, this);
19611 * Updates the box title
19612 * @param {String} html to set the title to.
19614 setTitle : function(value)
19616 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19618 onAddPane : function(pane)
19620 //Roo.log('addpane');
19622 // tabs are rendere left to right..
19623 var ctr = this.el.select('.nav-tabs', true).first();
19626 var existing = ctr.select('.nav-tab',true);
19627 var qty = existing.getCount();;
19630 var tab = ctr.createChild({
19632 cls : 'nav-tab' + (qty ? '' : ' active'),
19640 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19643 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19645 pane.el.addClass('active');
19650 onTabClick : function(ev,un,ob,pane)
19652 //Roo.log('tab - prev default');
19653 ev.preventDefault();
19656 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19657 pane.tab.addClass('active');
19658 //Roo.log(pane.title);
19659 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19660 // technically we should have a deactivate event.. but maybe add later.
19661 // and it should not de-activate the selected tab...
19663 pane.el.addClass('active');
19664 pane.fireEvent('activate');
19679 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19681 * @class Roo.bootstrap.TabPane
19682 * @extends Roo.bootstrap.Component
19683 * Bootstrap TabPane class
19684 * @cfg {Boolean} active (false | true) Default false
19685 * @cfg {String} title title of panel
19689 * Create a new TabPane
19690 * @param {Object} config The config object
19693 Roo.bootstrap.dash.TabPane = function(config){
19694 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19698 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19703 // the tabBox that this is attached to.
19706 getAutoCreate : function()
19714 cfg.cls += ' active';
19719 initEvents : function()
19721 //Roo.log('trigger add pane handler');
19722 this.parent().fireEvent('addpane', this)
19726 * Updates the tab title
19727 * @param {String} html to set the title to.
19729 setTitle: function(str)
19735 this.tab.select('a'.true).first().dom.innerHTML = str;
19752 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19755 * @class Roo.bootstrap.menu.Menu
19756 * @extends Roo.bootstrap.Component
19757 * Bootstrap Menu class - container for Menu
19758 * @cfg {String} html Text of the menu
19759 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19760 * @cfg {String} icon Font awesome icon
19761 * @cfg {String} pos Menu align to (top | bottom) default bottom
19765 * Create a new Menu
19766 * @param {Object} config The config object
19770 Roo.bootstrap.menu.Menu = function(config){
19771 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19775 * @event beforeshow
19776 * Fires before this menu is displayed
19777 * @param {Roo.bootstrap.menu.Menu} this
19781 * @event beforehide
19782 * Fires before this menu is hidden
19783 * @param {Roo.bootstrap.menu.Menu} this
19788 * Fires after this menu is displayed
19789 * @param {Roo.bootstrap.menu.Menu} this
19794 * Fires after this menu is hidden
19795 * @param {Roo.bootstrap.menu.Menu} this
19800 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19801 * @param {Roo.bootstrap.menu.Menu} this
19802 * @param {Roo.EventObject} e
19809 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19813 weight : 'default',
19818 getChildContainer : function() {
19819 if(this.isSubMenu){
19823 return this.el.select('ul.dropdown-menu', true).first();
19826 getAutoCreate : function()
19831 cls : 'roo-menu-text',
19839 cls : 'fa ' + this.icon
19850 cls : 'dropdown-button btn btn-' + this.weight,
19855 cls : 'dropdown-toggle btn btn-' + this.weight,
19865 cls : 'dropdown-menu'
19871 if(this.pos == 'top'){
19872 cfg.cls += ' dropup';
19875 if(this.isSubMenu){
19878 cls : 'dropdown-menu'
19885 onRender : function(ct, position)
19887 this.isSubMenu = ct.hasClass('dropdown-submenu');
19889 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19892 initEvents : function()
19894 if(this.isSubMenu){
19898 this.hidden = true;
19900 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19901 this.triggerEl.on('click', this.onTriggerPress, this);
19903 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19904 this.buttonEl.on('click', this.onClick, this);
19910 if(this.isSubMenu){
19914 return this.el.select('ul.dropdown-menu', true).first();
19917 onClick : function(e)
19919 this.fireEvent("click", this, e);
19922 onTriggerPress : function(e)
19924 if (this.isVisible()) {
19931 isVisible : function(){
19932 return !this.hidden;
19937 this.fireEvent("beforeshow", this);
19939 this.hidden = false;
19940 this.el.addClass('open');
19942 Roo.get(document).on("mouseup", this.onMouseUp, this);
19944 this.fireEvent("show", this);
19951 this.fireEvent("beforehide", this);
19953 this.hidden = true;
19954 this.el.removeClass('open');
19956 Roo.get(document).un("mouseup", this.onMouseUp);
19958 this.fireEvent("hide", this);
19961 onMouseUp : function()
19975 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19978 * @class Roo.bootstrap.menu.Item
19979 * @extends Roo.bootstrap.Component
19980 * Bootstrap MenuItem class
19981 * @cfg {Boolean} submenu (true | false) default false
19982 * @cfg {String} html text of the item
19983 * @cfg {String} href the link
19984 * @cfg {Boolean} disable (true | false) default false
19985 * @cfg {Boolean} preventDefault (true | false) default true
19986 * @cfg {String} icon Font awesome icon
19987 * @cfg {String} pos Submenu align to (left | right) default right
19991 * Create a new Item
19992 * @param {Object} config The config object
19996 Roo.bootstrap.menu.Item = function(config){
19997 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20001 * Fires when the mouse is hovering over this menu
20002 * @param {Roo.bootstrap.menu.Item} this
20003 * @param {Roo.EventObject} e
20008 * Fires when the mouse exits this menu
20009 * @param {Roo.bootstrap.menu.Item} this
20010 * @param {Roo.EventObject} e
20016 * The raw click event for the entire grid.
20017 * @param {Roo.EventObject} e
20023 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20028 preventDefault: true,
20033 getAutoCreate : function()
20038 cls : 'roo-menu-item-text',
20046 cls : 'fa ' + this.icon
20055 href : this.href || '#',
20062 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20066 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20068 if(this.pos == 'left'){
20069 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20076 initEvents : function()
20078 this.el.on('mouseover', this.onMouseOver, this);
20079 this.el.on('mouseout', this.onMouseOut, this);
20081 this.el.select('a', true).first().on('click', this.onClick, this);
20085 onClick : function(e)
20087 if(this.preventDefault){
20088 e.preventDefault();
20091 this.fireEvent("click", this, e);
20094 onMouseOver : function(e)
20096 if(this.submenu && this.pos == 'left'){
20097 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20100 this.fireEvent("mouseover", this, e);
20103 onMouseOut : function(e)
20105 this.fireEvent("mouseout", this, e);
20117 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20120 * @class Roo.bootstrap.menu.Separator
20121 * @extends Roo.bootstrap.Component
20122 * Bootstrap Separator class
20125 * Create a new Separator
20126 * @param {Object} config The config object
20130 Roo.bootstrap.menu.Separator = function(config){
20131 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20134 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20136 getAutoCreate : function(){