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;
5161 if(ds.getCount() > 0){
5162 ds.data.each(function(d,rowIndex){
5163 var row = this.renderRow(cm, ds, rowIndex);
5165 tbody.createChild(row);
5169 if(row.cellObjects.length){
5170 Roo.each(row.cellObjects, function(r){
5171 _this.renderCellObject(r);
5178 Roo.each(this.el.select('tbody td', true).elements, function(e){
5179 e.on('mouseover', _this.onMouseover, _this);
5182 Roo.each(this.el.select('tbody td', true).elements, function(e){
5183 e.on('mouseout', _this.onMouseout, _this);
5186 //if(this.loadMask){
5187 // this.maskEl.hide();
5192 onUpdate : function(ds,record)
5194 this.refreshRow(record);
5196 onRemove : function(ds, record, index, isUpdate){
5197 if(isUpdate !== true){
5198 this.fireEvent("beforerowremoved", this, index, record);
5200 var bt = this.mainBody.dom;
5202 bt.removeChild(bt.rows[index]);
5205 if(isUpdate !== true){
5206 //this.stripeRows(index);
5207 //this.syncRowHeights(index, index);
5209 this.fireEvent("rowremoved", this, index, record);
5214 refreshRow : function(record){
5215 var ds = this.store, index;
5216 if(typeof record == 'number'){
5218 record = ds.getAt(index);
5220 index = ds.indexOf(record);
5222 this.insertRow(ds, index, true);
5223 this.onRemove(ds, record, index+1, true);
5224 //this.syncRowHeights(index, index);
5226 this.fireEvent("rowupdated", this, index, record);
5229 insertRow : function(dm, rowIndex, isUpdate){
5232 this.fireEvent("beforerowsinserted", this, rowIndex);
5234 //var s = this.getScrollState();
5235 var row = this.renderRow(this.cm, this.store, rowIndex);
5236 // insert before rowIndex..
5237 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5241 if(row.cellObjects.length){
5242 Roo.each(row.cellObjects, function(r){
5243 _this.renderCellObject(r);
5248 this.fireEvent("rowsinserted", this, rowIndex);
5249 //this.syncRowHeights(firstRow, lastRow);
5250 //this.stripeRows(firstRow);
5257 getRowDom : function(rowIndex)
5259 // not sure if I need to check this.. but let's do it anyway..
5260 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5261 this.mainBody.dom.rows[rowIndex] : false
5263 // returns the object tree for a tr..
5266 renderRow : function(cm, ds, rowIndex) {
5268 var d = ds.getAt(rowIndex);
5275 var cellObjects = [];
5277 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5278 var config = cm.config[i];
5280 var renderer = cm.getRenderer(i);
5284 if(typeof(renderer) !== 'undefined'){
5285 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5287 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5288 // and are rendered into the cells after the row is rendered - using the id for the element.
5290 if(typeof(value) === 'object'){
5300 rowIndex : rowIndex,
5305 this.fireEvent('rowclass', this, rowcfg);
5309 cls : rowcfg.rowClass,
5311 html: (typeof(value) === 'object') ? '' : value
5318 if(typeof(config.hidden) != 'undefined' && config.hidden){
5319 td.style += ' display:none;';
5322 if(typeof(config.align) != 'undefined' && config.align.length){
5323 td.style += ' text-align:' + config.align + ';';
5326 if(typeof(config.width) != 'undefined'){
5327 td.style += ' width:' + config.width + 'px;';
5334 row.cellObjects = cellObjects;
5342 onBeforeLoad : function()
5344 //Roo.log('ds onBeforeLoad');
5348 //if(this.loadMask){
5349 // this.maskEl.show();
5355 this.el.select('tbody', true).first().dom.innerHTML = '';
5358 getSelectionModel : function(){
5360 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5362 return this.selModel;
5365 * Render the Roo.bootstrap object from renderder
5367 renderCellObject : function(r)
5371 var t = r.cfg.render(r.container);
5374 Roo.each(r.cfg.cn, function(c){
5376 container: t.getChildContainer(),
5379 _this.renderCellObject(child);
5396 * @class Roo.bootstrap.TableCell
5397 * @extends Roo.bootstrap.Component
5398 * Bootstrap TableCell class
5399 * @cfg {String} html cell contain text
5400 * @cfg {String} cls cell class
5401 * @cfg {String} tag cell tag (td|th) default td
5402 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5403 * @cfg {String} align Aligns the content in a cell
5404 * @cfg {String} axis Categorizes cells
5405 * @cfg {String} bgcolor Specifies the background color of a cell
5406 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5407 * @cfg {Number} colspan Specifies the number of columns a cell should span
5408 * @cfg {String} headers Specifies one or more header cells a cell is related to
5409 * @cfg {Number} height Sets the height of a cell
5410 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5411 * @cfg {Number} rowspan Sets the number of rows a cell should span
5412 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5413 * @cfg {String} valign Vertical aligns the content in a cell
5414 * @cfg {Number} width Specifies the width of a cell
5417 * Create a new TableCell
5418 * @param {Object} config The config object
5421 Roo.bootstrap.TableCell = function(config){
5422 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5425 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5445 getAutoCreate : function(){
5446 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5466 cfg.align=this.align
5472 cfg.bgcolor=this.bgcolor
5475 cfg.charoff=this.charoff
5478 cfg.colspan=this.colspan
5481 cfg.headers=this.headers
5484 cfg.height=this.height
5487 cfg.nowrap=this.nowrap
5490 cfg.rowspan=this.rowspan
5493 cfg.scope=this.scope
5496 cfg.valign=this.valign
5499 cfg.width=this.width
5518 * @class Roo.bootstrap.TableRow
5519 * @extends Roo.bootstrap.Component
5520 * Bootstrap TableRow class
5521 * @cfg {String} cls row class
5522 * @cfg {String} align Aligns the content in a table row
5523 * @cfg {String} bgcolor Specifies a background color for a table row
5524 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5525 * @cfg {String} valign Vertical aligns the content in a table row
5528 * Create a new TableRow
5529 * @param {Object} config The config object
5532 Roo.bootstrap.TableRow = function(config){
5533 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5536 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5544 getAutoCreate : function(){
5545 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5555 cfg.align = this.align;
5558 cfg.bgcolor = this.bgcolor;
5561 cfg.charoff = this.charoff;
5564 cfg.valign = this.valign;
5582 * @class Roo.bootstrap.TableBody
5583 * @extends Roo.bootstrap.Component
5584 * Bootstrap TableBody class
5585 * @cfg {String} cls element class
5586 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5587 * @cfg {String} align Aligns the content inside the element
5588 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5589 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5592 * Create a new TableBody
5593 * @param {Object} config The config object
5596 Roo.bootstrap.TableBody = function(config){
5597 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5600 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5608 getAutoCreate : function(){
5609 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5623 cfg.align = this.align;
5626 cfg.charoff = this.charoff;
5629 cfg.valign = this.valign;
5636 // initEvents : function()
5643 // this.store = Roo.factory(this.store, Roo.data);
5644 // this.store.on('load', this.onLoad, this);
5646 // this.store.load();
5650 // onLoad: function ()
5652 // this.fireEvent('load', this);
5662 * Ext JS Library 1.1.1
5663 * Copyright(c) 2006-2007, Ext JS, LLC.
5665 * Originally Released Under LGPL - original licence link has changed is not relivant.
5668 * <script type="text/javascript">
5671 // as we use this in bootstrap.
5672 Roo.namespace('Roo.form');
5674 * @class Roo.form.Action
5675 * Internal Class used to handle form actions
5677 * @param {Roo.form.BasicForm} el The form element or its id
5678 * @param {Object} config Configuration options
5683 // define the action interface
5684 Roo.form.Action = function(form, options){
5686 this.options = options || {};
5689 * Client Validation Failed
5692 Roo.form.Action.CLIENT_INVALID = 'client';
5694 * Server Validation Failed
5697 Roo.form.Action.SERVER_INVALID = 'server';
5699 * Connect to Server Failed
5702 Roo.form.Action.CONNECT_FAILURE = 'connect';
5704 * Reading Data from Server Failed
5707 Roo.form.Action.LOAD_FAILURE = 'load';
5709 Roo.form.Action.prototype = {
5711 failureType : undefined,
5712 response : undefined,
5716 run : function(options){
5721 success : function(response){
5726 handleResponse : function(response){
5730 // default connection failure
5731 failure : function(response){
5733 this.response = response;
5734 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5735 this.form.afterAction(this, false);
5738 processResponse : function(response){
5739 this.response = response;
5740 if(!response.responseText){
5743 this.result = this.handleResponse(response);
5747 // utility functions used internally
5748 getUrl : function(appendParams){
5749 var url = this.options.url || this.form.url || this.form.el.dom.action;
5751 var p = this.getParams();
5753 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5759 getMethod : function(){
5760 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5763 getParams : function(){
5764 var bp = this.form.baseParams;
5765 var p = this.options.params;
5767 if(typeof p == "object"){
5768 p = Roo.urlEncode(Roo.applyIf(p, bp));
5769 }else if(typeof p == 'string' && bp){
5770 p += '&' + Roo.urlEncode(bp);
5773 p = Roo.urlEncode(bp);
5778 createCallback : function(){
5780 success: this.success,
5781 failure: this.failure,
5783 timeout: (this.form.timeout*1000),
5784 upload: this.form.fileUpload ? this.success : undefined
5789 Roo.form.Action.Submit = function(form, options){
5790 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5793 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5796 haveProgress : false,
5797 uploadComplete : false,
5799 // uploadProgress indicator.
5800 uploadProgress : function()
5802 if (!this.form.progressUrl) {
5806 if (!this.haveProgress) {
5807 Roo.MessageBox.progress("Uploading", "Uploading");
5809 if (this.uploadComplete) {
5810 Roo.MessageBox.hide();
5814 this.haveProgress = true;
5816 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5818 var c = new Roo.data.Connection();
5820 url : this.form.progressUrl,
5825 success : function(req){
5826 //console.log(data);
5830 rdata = Roo.decode(req.responseText)
5832 Roo.log("Invalid data from server..");
5836 if (!rdata || !rdata.success) {
5838 Roo.MessageBox.alert(Roo.encode(rdata));
5841 var data = rdata.data;
5843 if (this.uploadComplete) {
5844 Roo.MessageBox.hide();
5849 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5850 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5853 this.uploadProgress.defer(2000,this);
5856 failure: function(data) {
5857 Roo.log('progress url failed ');
5868 // run get Values on the form, so it syncs any secondary forms.
5869 this.form.getValues();
5871 var o = this.options;
5872 var method = this.getMethod();
5873 var isPost = method == 'POST';
5874 if(o.clientValidation === false || this.form.isValid()){
5876 if (this.form.progressUrl) {
5877 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5878 (new Date() * 1) + '' + Math.random());
5883 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5884 form:this.form.el.dom,
5885 url:this.getUrl(!isPost),
5887 params:isPost ? this.getParams() : null,
5888 isUpload: this.form.fileUpload
5891 this.uploadProgress();
5893 }else if (o.clientValidation !== false){ // client validation failed
5894 this.failureType = Roo.form.Action.CLIENT_INVALID;
5895 this.form.afterAction(this, false);
5899 success : function(response)
5901 this.uploadComplete= true;
5902 if (this.haveProgress) {
5903 Roo.MessageBox.hide();
5907 var result = this.processResponse(response);
5908 if(result === true || result.success){
5909 this.form.afterAction(this, true);
5913 this.form.markInvalid(result.errors);
5914 this.failureType = Roo.form.Action.SERVER_INVALID;
5916 this.form.afterAction(this, false);
5918 failure : function(response)
5920 this.uploadComplete= true;
5921 if (this.haveProgress) {
5922 Roo.MessageBox.hide();
5925 this.response = response;
5926 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5927 this.form.afterAction(this, false);
5930 handleResponse : function(response){
5931 if(this.form.errorReader){
5932 var rs = this.form.errorReader.read(response);
5935 for(var i = 0, len = rs.records.length; i < len; i++) {
5936 var r = rs.records[i];
5940 if(errors.length < 1){
5944 success : rs.success,
5950 ret = Roo.decode(response.responseText);
5954 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5964 Roo.form.Action.Load = function(form, options){
5965 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5966 this.reader = this.form.reader;
5969 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5974 Roo.Ajax.request(Roo.apply(
5975 this.createCallback(), {
5976 method:this.getMethod(),
5977 url:this.getUrl(false),
5978 params:this.getParams()
5982 success : function(response){
5984 var result = this.processResponse(response);
5985 if(result === true || !result.success || !result.data){
5986 this.failureType = Roo.form.Action.LOAD_FAILURE;
5987 this.form.afterAction(this, false);
5990 this.form.clearInvalid();
5991 this.form.setValues(result.data);
5992 this.form.afterAction(this, true);
5995 handleResponse : function(response){
5996 if(this.form.reader){
5997 var rs = this.form.reader.read(response);
5998 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6000 success : rs.success,
6004 return Roo.decode(response.responseText);
6008 Roo.form.Action.ACTION_TYPES = {
6009 'load' : Roo.form.Action.Load,
6010 'submit' : Roo.form.Action.Submit
6019 * @class Roo.bootstrap.Form
6020 * @extends Roo.bootstrap.Component
6021 * Bootstrap Form class
6022 * @cfg {String} method GET | POST (default POST)
6023 * @cfg {String} labelAlign top | left (default top)
6024 * @cfg {String} align left | right - for navbars
6029 * @param {Object} config The config object
6033 Roo.bootstrap.Form = function(config){
6034 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6037 * @event clientvalidation
6038 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6039 * @param {Form} this
6040 * @param {Boolean} valid true if the form has passed client-side validation
6042 clientvalidation: true,
6044 * @event beforeaction
6045 * Fires before any action is performed. Return false to cancel the action.
6046 * @param {Form} this
6047 * @param {Action} action The action to be performed
6051 * @event actionfailed
6052 * Fires when an action fails.
6053 * @param {Form} this
6054 * @param {Action} action The action that failed
6056 actionfailed : true,
6058 * @event actioncomplete
6059 * Fires when an action is completed.
6060 * @param {Form} this
6061 * @param {Action} action The action that completed
6063 actioncomplete : true
6068 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6071 * @cfg {String} method
6072 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6077 * The URL to use for form actions if one isn't supplied in the action options.
6080 * @cfg {Boolean} fileUpload
6081 * Set to true if this form is a file upload.
6085 * @cfg {Object} baseParams
6086 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6090 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6094 * @cfg {Sting} align (left|right) for navbar forms
6099 activeAction : null,
6102 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6103 * element by passing it or its id or mask the form itself by passing in true.
6106 waitMsgTarget : false,
6111 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6112 * element by passing it or its id or mask the form itself by passing in true.
6116 getAutoCreate : function(){
6120 method : this.method || 'POST',
6121 id : this.id || Roo.id(),
6124 if (this.parent().xtype.match(/^Nav/)) {
6125 cfg.cls = 'navbar-form navbar-' + this.align;
6129 if (this.labelAlign == 'left' ) {
6130 cfg.cls += ' form-horizontal';
6136 initEvents : function()
6138 this.el.on('submit', this.onSubmit, this);
6139 // this was added as random key presses on the form where triggering form submit.
6140 this.el.on('keypress', function(e) {
6141 if (e.getCharCode() != 13) {
6144 // we might need to allow it for textareas.. and some other items.
6145 // check e.getTarget().
6147 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6151 Roo.log("keypress blocked");
6159 onSubmit : function(e){
6164 * Returns true if client-side validation on the form is successful.
6167 isValid : function(){
6168 var items = this.getItems();
6170 items.each(function(f){
6179 * Returns true if any fields in this form have changed since their original load.
6182 isDirty : function(){
6184 var items = this.getItems();
6185 items.each(function(f){
6195 * Performs a predefined action (submit or load) or custom actions you define on this form.
6196 * @param {String} actionName The name of the action type
6197 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6198 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6199 * accept other config options):
6201 Property Type Description
6202 ---------------- --------------- ----------------------------------------------------------------------------------
6203 url String The url for the action (defaults to the form's url)
6204 method String The form method to use (defaults to the form's method, or POST if not defined)
6205 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6206 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6207 validate the form on the client (defaults to false)
6209 * @return {BasicForm} this
6211 doAction : function(action, options){
6212 if(typeof action == 'string'){
6213 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6215 if(this.fireEvent('beforeaction', this, action) !== false){
6216 this.beforeAction(action);
6217 action.run.defer(100, action);
6223 beforeAction : function(action){
6224 var o = action.options;
6226 // not really supported yet.. ??
6228 //if(this.waitMsgTarget === true){
6229 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6230 //}else if(this.waitMsgTarget){
6231 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6232 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6234 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6240 afterAction : function(action, success){
6241 this.activeAction = null;
6242 var o = action.options;
6244 //if(this.waitMsgTarget === true){
6246 //}else if(this.waitMsgTarget){
6247 // this.waitMsgTarget.unmask();
6249 // Roo.MessageBox.updateProgress(1);
6250 // Roo.MessageBox.hide();
6257 Roo.callback(o.success, o.scope, [this, action]);
6258 this.fireEvent('actioncomplete', this, action);
6262 // failure condition..
6263 // we have a scenario where updates need confirming.
6264 // eg. if a locking scenario exists..
6265 // we look for { errors : { needs_confirm : true }} in the response.
6267 (typeof(action.result) != 'undefined') &&
6268 (typeof(action.result.errors) != 'undefined') &&
6269 (typeof(action.result.errors.needs_confirm) != 'undefined')
6272 Roo.log("not supported yet");
6275 Roo.MessageBox.confirm(
6276 "Change requires confirmation",
6277 action.result.errorMsg,
6282 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6292 Roo.callback(o.failure, o.scope, [this, action]);
6293 // show an error message if no failed handler is set..
6294 if (!this.hasListener('actionfailed')) {
6295 Roo.log("need to add dialog support");
6297 Roo.MessageBox.alert("Error",
6298 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6299 action.result.errorMsg :
6300 "Saving Failed, please check your entries or try again"
6305 this.fireEvent('actionfailed', this, action);
6310 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6311 * @param {String} id The value to search for
6314 findField : function(id){
6315 var items = this.getItems();
6316 var field = items.get(id);
6318 items.each(function(f){
6319 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6326 return field || null;
6329 * Mark fields in this form invalid in bulk.
6330 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6331 * @return {BasicForm} this
6333 markInvalid : function(errors){
6334 if(errors instanceof Array){
6335 for(var i = 0, len = errors.length; i < len; i++){
6336 var fieldError = errors[i];
6337 var f = this.findField(fieldError.id);
6339 f.markInvalid(fieldError.msg);
6345 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6346 field.markInvalid(errors[id]);
6350 //Roo.each(this.childForms || [], function (f) {
6351 // f.markInvalid(errors);
6358 * Set values for fields in this form in bulk.
6359 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6360 * @return {BasicForm} this
6362 setValues : function(values){
6363 if(values instanceof Array){ // array of objects
6364 for(var i = 0, len = values.length; i < len; i++){
6366 var f = this.findField(v.id);
6368 f.setValue(v.value);
6369 if(this.trackResetOnLoad){
6370 f.originalValue = f.getValue();
6374 }else{ // object hash
6377 if(typeof values[id] != 'function' && (field = this.findField(id))){
6379 if (field.setFromData &&
6381 field.displayField &&
6382 // combos' with local stores can
6383 // be queried via setValue()
6384 // to set their value..
6385 (field.store && !field.store.isLocal)
6389 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6390 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6391 field.setFromData(sd);
6394 field.setValue(values[id]);
6398 if(this.trackResetOnLoad){
6399 field.originalValue = field.getValue();
6405 //Roo.each(this.childForms || [], function (f) {
6406 // f.setValues(values);
6413 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6414 * they are returned as an array.
6415 * @param {Boolean} asString
6418 getValues : function(asString){
6419 //if (this.childForms) {
6420 // copy values from the child forms
6421 // Roo.each(this.childForms, function (f) {
6422 // this.setValues(f.getValues());
6428 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6429 if(asString === true){
6432 return Roo.urlDecode(fs);
6436 * Returns the fields in this form as an object with key/value pairs.
6437 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6440 getFieldValues : function(with_hidden)
6442 var items = this.getItems();
6444 items.each(function(f){
6448 var v = f.getValue();
6449 if (f.inputType =='radio') {
6450 if (typeof(ret[f.getName()]) == 'undefined') {
6451 ret[f.getName()] = ''; // empty..
6454 if (!f.el.dom.checked) {
6462 // not sure if this supported any more..
6463 if ((typeof(v) == 'object') && f.getRawValue) {
6464 v = f.getRawValue() ; // dates..
6466 // combo boxes where name != hiddenName...
6467 if (f.name != f.getName()) {
6468 ret[f.name] = f.getRawValue();
6470 ret[f.getName()] = v;
6477 * Clears all invalid messages in this form.
6478 * @return {BasicForm} this
6480 clearInvalid : function(){
6481 var items = this.getItems();
6483 items.each(function(f){
6494 * @return {BasicForm} this
6497 var items = this.getItems();
6498 items.each(function(f){
6502 Roo.each(this.childForms || [], function (f) {
6509 getItems : function()
6511 var r=new Roo.util.MixedCollection(false, function(o){
6512 return o.id || (o.id = Roo.id());
6514 var iter = function(el) {
6521 Roo.each(el.items,function(e) {
6540 * Ext JS Library 1.1.1
6541 * Copyright(c) 2006-2007, Ext JS, LLC.
6543 * Originally Released Under LGPL - original licence link has changed is not relivant.
6546 * <script type="text/javascript">
6549 * @class Roo.form.VTypes
6550 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6553 Roo.form.VTypes = function(){
6554 // closure these in so they are only created once.
6555 var alpha = /^[a-zA-Z_]+$/;
6556 var alphanum = /^[a-zA-Z0-9_]+$/;
6557 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6558 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6560 // All these messages and functions are configurable
6563 * The function used to validate email addresses
6564 * @param {String} value The email address
6566 'email' : function(v){
6567 return email.test(v);
6570 * The error text to display when the email validation function returns false
6573 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6575 * The keystroke filter mask to be applied on email input
6578 'emailMask' : /[a-z0-9_\.\-@]/i,
6581 * The function used to validate URLs
6582 * @param {String} value The URL
6584 'url' : function(v){
6588 * The error text to display when the url validation function returns false
6591 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6594 * The function used to validate alpha values
6595 * @param {String} value The value
6597 'alpha' : function(v){
6598 return alpha.test(v);
6601 * The error text to display when the alpha validation function returns false
6604 'alphaText' : 'This field should only contain letters and _',
6606 * The keystroke filter mask to be applied on alpha input
6609 'alphaMask' : /[a-z_]/i,
6612 * The function used to validate alphanumeric values
6613 * @param {String} value The value
6615 'alphanum' : function(v){
6616 return alphanum.test(v);
6619 * The error text to display when the alphanumeric validation function returns false
6622 'alphanumText' : 'This field should only contain letters, numbers and _',
6624 * The keystroke filter mask to be applied on alphanumeric input
6627 'alphanumMask' : /[a-z0-9_]/i
6637 * @class Roo.bootstrap.Input
6638 * @extends Roo.bootstrap.Component
6639 * Bootstrap Input class
6640 * @cfg {Boolean} disabled is it disabled
6641 * @cfg {String} fieldLabel - the label associated
6642 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6643 * @cfg {String} name name of the input
6644 * @cfg {string} fieldLabel - the label associated
6645 * @cfg {string} inputType - input / file submit ...
6646 * @cfg {string} placeholder - placeholder to put in text.
6647 * @cfg {string} before - input group add on before
6648 * @cfg {string} after - input group add on after
6649 * @cfg {string} size - (lg|sm) or leave empty..
6650 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6651 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6652 * @cfg {Number} md colspan out of 12 for computer-sized screens
6653 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6654 * @cfg {string} value default value of the input
6655 * @cfg {Number} labelWidth set the width of label (0-12)
6656 * @cfg {String} labelAlign (top|left)
6657 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6658 * @cfg {String} align (left|center|right) Default left
6662 * Create a new Input
6663 * @param {Object} config The config object
6666 Roo.bootstrap.Input = function(config){
6667 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6672 * Fires when this field receives input focus.
6673 * @param {Roo.form.Field} this
6678 * Fires when this field loses input focus.
6679 * @param {Roo.form.Field} this
6684 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6685 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6686 * @param {Roo.form.Field} this
6687 * @param {Roo.EventObject} e The event object
6692 * Fires just before the field blurs if the field value has changed.
6693 * @param {Roo.form.Field} this
6694 * @param {Mixed} newValue The new value
6695 * @param {Mixed} oldValue The original value
6700 * Fires after the field has been marked as invalid.
6701 * @param {Roo.form.Field} this
6702 * @param {String} msg The validation message
6707 * Fires after the field has been validated with no errors.
6708 * @param {Roo.form.Field} this
6713 * Fires after the key up
6714 * @param {Roo.form.Field} this
6715 * @param {Roo.EventObject} e The event Object
6721 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6723 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6724 automatic validation (defaults to "keyup").
6726 validationEvent : "keyup",
6728 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6730 validateOnBlur : true,
6732 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6734 validationDelay : 250,
6736 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6738 focusClass : "x-form-focus", // not needed???
6742 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6744 invalidClass : "has-error",
6747 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6749 selectOnFocus : false,
6752 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6756 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6761 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6763 disableKeyFilter : false,
6766 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6770 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6774 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6776 blankText : "This field is required",
6779 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6783 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6785 maxLength : Number.MAX_VALUE,
6787 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6789 minLengthText : "The minimum length for this field is {0}",
6791 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6793 maxLengthText : "The maximum length for this field is {0}",
6797 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6798 * If available, this function will be called only after the basic validators all return true, and will be passed the
6799 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6803 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6804 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6805 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6809 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6832 formatedValue : false,
6834 parentLabelAlign : function()
6837 while (parent.parent()) {
6838 parent = parent.parent();
6839 if (typeof(parent.labelAlign) !='undefined') {
6840 return parent.labelAlign;
6847 getAutoCreate : function(){
6849 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6855 if(this.inputType != 'hidden'){
6856 cfg.cls = 'form-group' //input-group
6862 type : this.inputType,
6864 cls : 'form-control',
6865 placeholder : this.placeholder || ''
6870 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6873 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6874 input.maxLength = this.maxLength;
6877 if (this.disabled) {
6878 input.disabled=true;
6881 if (this.readOnly) {
6882 input.readonly=true;
6886 input.name = this.name;
6889 input.cls += ' input-' + this.size;
6892 ['xs','sm','md','lg'].map(function(size){
6893 if (settings[size]) {
6894 cfg.cls += ' col-' + size + '-' + settings[size];
6898 var inputblock = input;
6900 if (this.before || this.after) {
6903 cls : 'input-group',
6906 if (this.before && typeof(this.before) == 'string') {
6908 inputblock.cn.push({
6910 cls : 'roo-input-before input-group-addon',
6914 if (this.before && typeof(this.before) == 'object') {
6915 this.before = Roo.factory(this.before);
6916 Roo.log(this.before);
6917 inputblock.cn.push({
6919 cls : 'roo-input-before input-group-' +
6920 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6924 inputblock.cn.push(input);
6926 if (this.after && typeof(this.after) == 'string') {
6927 inputblock.cn.push({
6929 cls : 'roo-input-after input-group-addon',
6933 if (this.after && typeof(this.after) == 'object') {
6934 this.after = Roo.factory(this.after);
6935 Roo.log(this.after);
6936 inputblock.cn.push({
6938 cls : 'roo-input-after input-group-' +
6939 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6944 if (align ==='left' && this.fieldLabel.length) {
6945 Roo.log("left and has label");
6951 cls : 'control-label col-sm-' + this.labelWidth,
6952 html : this.fieldLabel
6956 cls : "col-sm-" + (12 - this.labelWidth),
6963 } else if ( this.fieldLabel.length) {
6969 //cls : 'input-group-addon',
6970 html : this.fieldLabel
6980 Roo.log(" no label && no align");
6989 Roo.log('input-parentType: ' + this.parentType);
6991 if (this.parentType === 'Navbar' && this.parent().bar) {
6992 cfg.cls += ' navbar-form';
7000 * return the real input element.
7002 inputEl: function ()
7004 return this.el.select('input.form-control',true).first();
7006 setDisabled : function(v)
7008 var i = this.inputEl().dom;
7010 i.removeAttribute('disabled');
7014 i.setAttribute('disabled','true');
7016 initEvents : function()
7019 this.inputEl().on("keydown" , this.fireKey, this);
7020 this.inputEl().on("focus", this.onFocus, this);
7021 this.inputEl().on("blur", this.onBlur, this);
7023 this.inputEl().relayEvent('keyup', this);
7025 // reference to original value for reset
7026 this.originalValue = this.getValue();
7027 //Roo.form.TextField.superclass.initEvents.call(this);
7028 if(this.validationEvent == 'keyup'){
7029 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7030 this.inputEl().on('keyup', this.filterValidation, this);
7032 else if(this.validationEvent !== false){
7033 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7036 if(this.selectOnFocus){
7037 this.on("focus", this.preFocus, this);
7040 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7041 this.inputEl().on("keypress", this.filterKeys, this);
7044 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7045 this.el.on("click", this.autoSize, this);
7048 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7049 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7052 if (typeof(this.before) == 'object') {
7053 this.before.render(this.el.select('.roo-input-before',true).first());
7055 if (typeof(this.after) == 'object') {
7056 this.after.render(this.el.select('.roo-input-after',true).first());
7061 filterValidation : function(e){
7062 if(!e.isNavKeyPress()){
7063 this.validationTask.delay(this.validationDelay);
7067 * Validates the field value
7068 * @return {Boolean} True if the value is valid, else false
7070 validate : function(){
7071 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7072 if(this.disabled || this.validateValue(this.getRawValue())){
7073 this.clearInvalid();
7081 * Validates a value according to the field's validation rules and marks the field as invalid
7082 * if the validation fails
7083 * @param {Mixed} value The value to validate
7084 * @return {Boolean} True if the value is valid, else false
7086 validateValue : function(value){
7087 if(value.length < 1) { // if it's blank
7088 if(this.allowBlank){
7089 this.clearInvalid();
7092 this.markInvalid(this.blankText);
7096 if(value.length < this.minLength){
7097 this.markInvalid(String.format(this.minLengthText, this.minLength));
7100 if(value.length > this.maxLength){
7101 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7105 var vt = Roo.form.VTypes;
7106 if(!vt[this.vtype](value, this)){
7107 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7111 if(typeof this.validator == "function"){
7112 var msg = this.validator(value);
7114 this.markInvalid(msg);
7118 if(this.regex && !this.regex.test(value)){
7119 this.markInvalid(this.regexText);
7128 fireKey : function(e){
7129 //Roo.log('field ' + e.getKey());
7130 if(e.isNavKeyPress()){
7131 this.fireEvent("specialkey", this, e);
7134 focus : function (selectText){
7136 this.inputEl().focus();
7137 if(selectText === true){
7138 this.inputEl().dom.select();
7144 onFocus : function(){
7145 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7146 // this.el.addClass(this.focusClass);
7149 this.hasFocus = true;
7150 this.startValue = this.getValue();
7151 this.fireEvent("focus", this);
7155 beforeBlur : Roo.emptyFn,
7159 onBlur : function(){
7161 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7162 //this.el.removeClass(this.focusClass);
7164 this.hasFocus = false;
7165 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7168 var v = this.getValue();
7169 if(String(v) !== String(this.startValue)){
7170 this.fireEvent('change', this, v, this.startValue);
7172 this.fireEvent("blur", this);
7176 * Resets the current field value to the originally loaded value and clears any validation messages
7179 this.setValue(this.originalValue);
7180 this.clearInvalid();
7183 * Returns the name of the field
7184 * @return {Mixed} name The name field
7186 getName: function(){
7190 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7191 * @return {Mixed} value The field value
7193 getValue : function(){
7195 var v = this.inputEl().getValue();
7200 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7201 * @return {Mixed} value The field value
7203 getRawValue : function(){
7204 var v = this.inputEl().getValue();
7210 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7211 * @param {Mixed} value The value to set
7213 setRawValue : function(v){
7214 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7217 selectText : function(start, end){
7218 var v = this.getRawValue();
7220 start = start === undefined ? 0 : start;
7221 end = end === undefined ? v.length : end;
7222 var d = this.inputEl().dom;
7223 if(d.setSelectionRange){
7224 d.setSelectionRange(start, end);
7225 }else if(d.createTextRange){
7226 var range = d.createTextRange();
7227 range.moveStart("character", start);
7228 range.moveEnd("character", v.length-end);
7235 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7236 * @param {Mixed} value The value to set
7238 setValue : function(v){
7241 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7247 processValue : function(value){
7248 if(this.stripCharsRe){
7249 var newValue = value.replace(this.stripCharsRe, '');
7250 if(newValue !== value){
7251 this.setRawValue(newValue);
7258 preFocus : function(){
7260 if(this.selectOnFocus){
7261 this.inputEl().dom.select();
7264 filterKeys : function(e){
7266 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7269 var c = e.getCharCode(), cc = String.fromCharCode(c);
7270 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7273 if(!this.maskRe.test(cc)){
7278 * Clear any invalid styles/messages for this field
7280 clearInvalid : function(){
7282 if(!this.el || this.preventMark){ // not rendered
7285 this.el.removeClass(this.invalidClass);
7287 switch(this.msgTarget){
7289 this.el.dom.qtip = '';
7292 this.el.dom.title = '';
7296 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7301 this.errorIcon.dom.qtip = '';
7302 this.errorIcon.hide();
7303 this.un('resize', this.alignErrorIcon, this);
7307 var t = Roo.getDom(this.msgTarget);
7309 t.style.display = 'none';
7313 this.fireEvent('valid', this);
7316 * Mark this field as invalid
7317 * @param {String} msg The validation message
7319 markInvalid : function(msg){
7320 if(!this.el || this.preventMark){ // not rendered
7323 this.el.addClass(this.invalidClass);
7325 msg = msg || this.invalidText;
7326 switch(this.msgTarget){
7328 this.el.dom.qtip = msg;
7329 this.el.dom.qclass = 'x-form-invalid-tip';
7330 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7331 Roo.QuickTips.enable();
7335 this.el.dom.title = msg;
7339 var elp = this.el.findParent('.x-form-element', 5, true);
7340 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7341 this.errorEl.setWidth(elp.getWidth(true)-20);
7343 this.errorEl.update(msg);
7344 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7347 if(!this.errorIcon){
7348 var elp = this.el.findParent('.x-form-element', 5, true);
7349 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7351 this.alignErrorIcon();
7352 this.errorIcon.dom.qtip = msg;
7353 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7354 this.errorIcon.show();
7355 this.on('resize', this.alignErrorIcon, this);
7358 var t = Roo.getDom(this.msgTarget);
7360 t.style.display = this.msgDisplay;
7364 this.fireEvent('invalid', this, msg);
7367 SafariOnKeyDown : function(event)
7369 // this is a workaround for a password hang bug on chrome/ webkit.
7371 var isSelectAll = false;
7373 if(this.inputEl().dom.selectionEnd > 0){
7374 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7376 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7377 event.preventDefault();
7382 if(isSelectAll){ // backspace and delete key
7384 event.preventDefault();
7385 // this is very hacky as keydown always get's upper case.
7387 var cc = String.fromCharCode(event.getCharCode());
7388 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7392 adjustWidth : function(tag, w){
7393 tag = tag.toLowerCase();
7394 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7395 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7399 if(tag == 'textarea'){
7402 }else if(Roo.isOpera){
7406 if(tag == 'textarea'){
7425 * @class Roo.bootstrap.TextArea
7426 * @extends Roo.bootstrap.Input
7427 * Bootstrap TextArea class
7428 * @cfg {Number} cols Specifies the visible width of a text area
7429 * @cfg {Number} rows Specifies the visible number of lines in a text area
7430 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7431 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7432 * @cfg {string} html text
7435 * Create a new TextArea
7436 * @param {Object} config The config object
7439 Roo.bootstrap.TextArea = function(config){
7440 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7444 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7454 getAutoCreate : function(){
7456 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7467 value : this.value || '',
7468 html: this.html || '',
7469 cls : 'form-control',
7470 placeholder : this.placeholder || ''
7474 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7475 input.maxLength = this.maxLength;
7479 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7483 input.cols = this.cols;
7486 if (this.readOnly) {
7487 input.readonly = true;
7491 input.name = this.name;
7495 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7499 ['xs','sm','md','lg'].map(function(size){
7500 if (settings[size]) {
7501 cfg.cls += ' col-' + size + '-' + settings[size];
7505 var inputblock = input;
7507 if (this.before || this.after) {
7510 cls : 'input-group',
7514 inputblock.cn.push({
7516 cls : 'input-group-addon',
7520 inputblock.cn.push(input);
7522 inputblock.cn.push({
7524 cls : 'input-group-addon',
7531 if (align ==='left' && this.fieldLabel.length) {
7532 Roo.log("left and has label");
7538 cls : 'control-label col-sm-' + this.labelWidth,
7539 html : this.fieldLabel
7543 cls : "col-sm-" + (12 - this.labelWidth),
7550 } else if ( this.fieldLabel.length) {
7556 //cls : 'input-group-addon',
7557 html : this.fieldLabel
7567 Roo.log(" no label && no align");
7577 if (this.disabled) {
7578 input.disabled=true;
7585 * return the real textarea element.
7587 inputEl: function ()
7589 return this.el.select('textarea.form-control',true).first();
7597 * trigger field - base class for combo..
7602 * @class Roo.bootstrap.TriggerField
7603 * @extends Roo.bootstrap.Input
7604 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7605 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7606 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7607 * for which you can provide a custom implementation. For example:
7609 var trigger = new Roo.bootstrap.TriggerField();
7610 trigger.onTriggerClick = myTriggerFn;
7611 trigger.applyTo('my-field');
7614 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7615 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7616 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7617 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7619 * Create a new TriggerField.
7620 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7621 * to the base TextField)
7623 Roo.bootstrap.TriggerField = function(config){
7624 this.mimicing = false;
7625 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7628 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7630 * @cfg {String} triggerClass A CSS class to apply to the trigger
7633 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7637 /** @cfg {Boolean} grow @hide */
7638 /** @cfg {Number} growMin @hide */
7639 /** @cfg {Number} growMax @hide */
7645 autoSize: Roo.emptyFn,
7652 actionMode : 'wrap',
7656 getAutoCreate : function(){
7658 var align = this.labelAlign || this.parentLabelAlign();
7663 cls: 'form-group' //input-group
7670 type : this.inputType,
7671 cls : 'form-control',
7672 autocomplete: 'off',
7673 placeholder : this.placeholder || ''
7677 input.name = this.name;
7680 input.cls += ' input-' + this.size;
7683 if (this.disabled) {
7684 input.disabled=true;
7687 var inputblock = input;
7689 if (this.before || this.after) {
7692 cls : 'input-group',
7696 inputblock.cn.push({
7698 cls : 'input-group-addon',
7702 inputblock.cn.push(input);
7704 inputblock.cn.push({
7706 cls : 'input-group-addon',
7719 cls: 'form-hidden-field'
7727 Roo.log('multiple');
7735 cls: 'form-hidden-field'
7739 cls: 'select2-choices',
7743 cls: 'select2-search-field',
7756 cls: 'select2-container input-group',
7761 // cls: 'typeahead typeahead-long dropdown-menu',
7762 // style: 'display:none'
7770 cls : 'input-group-addon btn dropdown-toggle',
7778 cls: 'combobox-clear',
7792 combobox.cls += ' select2-container-multi';
7795 if (align ==='left' && this.fieldLabel.length) {
7797 Roo.log("left and has label");
7803 cls : 'control-label col-sm-' + this.labelWidth,
7804 html : this.fieldLabel
7808 cls : "col-sm-" + (12 - this.labelWidth),
7815 } else if ( this.fieldLabel.length) {
7821 //cls : 'input-group-addon',
7822 html : this.fieldLabel
7832 Roo.log(" no label && no align");
7839 ['xs','sm','md','lg'].map(function(size){
7840 if (settings[size]) {
7841 cfg.cls += ' col-' + size + '-' + settings[size];
7852 onResize : function(w, h){
7853 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7854 // if(typeof w == 'number'){
7855 // var x = w - this.trigger.getWidth();
7856 // this.inputEl().setWidth(this.adjustWidth('input', x));
7857 // this.trigger.setStyle('left', x+'px');
7862 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7865 getResizeEl : function(){
7866 return this.inputEl();
7870 getPositionEl : function(){
7871 return this.inputEl();
7875 alignErrorIcon : function(){
7876 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7880 initEvents : function(){
7884 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7885 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7887 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7888 if(this.hideTrigger){
7889 this.trigger.setDisplayed(false);
7891 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7895 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7898 //this.trigger.addClassOnOver('x-form-trigger-over');
7899 //this.trigger.addClassOnClick('x-form-trigger-click');
7902 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7906 createList : function()
7908 this.list = Roo.get(document.body).createChild({
7910 cls: 'typeahead typeahead-long dropdown-menu',
7911 style: 'display:none'
7916 initTrigger : function(){
7921 onDestroy : function(){
7923 this.trigger.removeAllListeners();
7924 // this.trigger.remove();
7927 // this.wrap.remove();
7929 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7933 onFocus : function(){
7934 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7937 this.wrap.addClass('x-trigger-wrap-focus');
7938 this.mimicing = true;
7939 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7940 if(this.monitorTab){
7941 this.el.on("keydown", this.checkTab, this);
7948 checkTab : function(e){
7949 if(e.getKey() == e.TAB){
7955 onBlur : function(){
7960 mimicBlur : function(e, t){
7962 if(!this.wrap.contains(t) && this.validateBlur()){
7969 triggerBlur : function(){
7970 this.mimicing = false;
7971 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7972 if(this.monitorTab){
7973 this.el.un("keydown", this.checkTab, this);
7975 //this.wrap.removeClass('x-trigger-wrap-focus');
7976 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7980 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7981 validateBlur : function(e, t){
7986 onDisable : function(){
7987 this.inputEl().dom.disabled = true;
7988 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7990 // this.wrap.addClass('x-item-disabled');
7995 onEnable : function(){
7996 this.inputEl().dom.disabled = false;
7997 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7999 // this.el.removeClass('x-item-disabled');
8004 onShow : function(){
8005 var ae = this.getActionEl();
8008 ae.dom.style.display = '';
8009 ae.dom.style.visibility = 'visible';
8015 onHide : function(){
8016 var ae = this.getActionEl();
8017 ae.dom.style.display = 'none';
8021 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8022 * by an implementing function.
8024 * @param {EventObject} e
8026 onTriggerClick : Roo.emptyFn
8030 * Ext JS Library 1.1.1
8031 * Copyright(c) 2006-2007, Ext JS, LLC.
8033 * Originally Released Under LGPL - original licence link has changed is not relivant.
8036 * <script type="text/javascript">
8041 * @class Roo.data.SortTypes
8043 * Defines the default sorting (casting?) comparison functions used when sorting data.
8045 Roo.data.SortTypes = {
8047 * Default sort that does nothing
8048 * @param {Mixed} s The value being converted
8049 * @return {Mixed} The comparison value
8056 * The regular expression used to strip tags
8060 stripTagsRE : /<\/?[^>]+>/gi,
8063 * Strips all HTML tags to sort on text only
8064 * @param {Mixed} s The value being converted
8065 * @return {String} The comparison value
8067 asText : function(s){
8068 return String(s).replace(this.stripTagsRE, "");
8072 * Strips all HTML tags to sort on text only - Case insensitive
8073 * @param {Mixed} s The value being converted
8074 * @return {String} The comparison value
8076 asUCText : function(s){
8077 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8081 * Case insensitive string
8082 * @param {Mixed} s The value being converted
8083 * @return {String} The comparison value
8085 asUCString : function(s) {
8086 return String(s).toUpperCase();
8091 * @param {Mixed} s The value being converted
8092 * @return {Number} The comparison value
8094 asDate : function(s) {
8098 if(s instanceof Date){
8101 return Date.parse(String(s));
8106 * @param {Mixed} s The value being converted
8107 * @return {Float} The comparison value
8109 asFloat : function(s) {
8110 var val = parseFloat(String(s).replace(/,/g, ""));
8111 if(isNaN(val)) val = 0;
8117 * @param {Mixed} s The value being converted
8118 * @return {Number} The comparison value
8120 asInt : function(s) {
8121 var val = parseInt(String(s).replace(/,/g, ""));
8122 if(isNaN(val)) val = 0;
8127 * Ext JS Library 1.1.1
8128 * Copyright(c) 2006-2007, Ext JS, LLC.
8130 * Originally Released Under LGPL - original licence link has changed is not relivant.
8133 * <script type="text/javascript">
8137 * @class Roo.data.Record
8138 * Instances of this class encapsulate both record <em>definition</em> information, and record
8139 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8140 * to access Records cached in an {@link Roo.data.Store} object.<br>
8142 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8143 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8146 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8148 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8149 * {@link #create}. The parameters are the same.
8150 * @param {Array} data An associative Array of data values keyed by the field name.
8151 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8152 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8153 * not specified an integer id is generated.
8155 Roo.data.Record = function(data, id){
8156 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8161 * Generate a constructor for a specific record layout.
8162 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8163 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8164 * Each field definition object may contain the following properties: <ul>
8165 * <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,
8166 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8167 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8168 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8169 * is being used, then this is a string containing the javascript expression to reference the data relative to
8170 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8171 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8172 * this may be omitted.</p></li>
8173 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8174 * <ul><li>auto (Default, implies no conversion)</li>
8179 * <li>date</li></ul></p></li>
8180 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8181 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8182 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8183 * by the Reader into an object that will be stored in the Record. It is passed the
8184 * following parameters:<ul>
8185 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8187 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8189 * <br>usage:<br><pre><code>
8190 var TopicRecord = Roo.data.Record.create(
8191 {name: 'title', mapping: 'topic_title'},
8192 {name: 'author', mapping: 'username'},
8193 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8194 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8195 {name: 'lastPoster', mapping: 'user2'},
8196 {name: 'excerpt', mapping: 'post_text'}
8199 var myNewRecord = new TopicRecord({
8200 title: 'Do my job please',
8203 lastPost: new Date(),
8204 lastPoster: 'Animal',
8205 excerpt: 'No way dude!'
8207 myStore.add(myNewRecord);
8212 Roo.data.Record.create = function(o){
8214 f.superclass.constructor.apply(this, arguments);
8216 Roo.extend(f, Roo.data.Record);
8217 var p = f.prototype;
8218 p.fields = new Roo.util.MixedCollection(false, function(field){
8221 for(var i = 0, len = o.length; i < len; i++){
8222 p.fields.add(new Roo.data.Field(o[i]));
8224 f.getField = function(name){
8225 return p.fields.get(name);
8230 Roo.data.Record.AUTO_ID = 1000;
8231 Roo.data.Record.EDIT = 'edit';
8232 Roo.data.Record.REJECT = 'reject';
8233 Roo.data.Record.COMMIT = 'commit';
8235 Roo.data.Record.prototype = {
8237 * Readonly flag - true if this record has been modified.
8246 join : function(store){
8251 * Set the named field to the specified value.
8252 * @param {String} name The name of the field to set.
8253 * @param {Object} value The value to set the field to.
8255 set : function(name, value){
8256 if(this.data[name] == value){
8263 if(typeof this.modified[name] == 'undefined'){
8264 this.modified[name] = this.data[name];
8266 this.data[name] = value;
8267 if(!this.editing && this.store){
8268 this.store.afterEdit(this);
8273 * Get the value of the named field.
8274 * @param {String} name The name of the field to get the value of.
8275 * @return {Object} The value of the field.
8277 get : function(name){
8278 return this.data[name];
8282 beginEdit : function(){
8283 this.editing = true;
8288 cancelEdit : function(){
8289 this.editing = false;
8290 delete this.modified;
8294 endEdit : function(){
8295 this.editing = false;
8296 if(this.dirty && this.store){
8297 this.store.afterEdit(this);
8302 * Usually called by the {@link Roo.data.Store} which owns the Record.
8303 * Rejects all changes made to the Record since either creation, or the last commit operation.
8304 * Modified fields are reverted to their original values.
8306 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8307 * of reject operations.
8309 reject : function(){
8310 var m = this.modified;
8312 if(typeof m[n] != "function"){
8313 this.data[n] = m[n];
8317 delete this.modified;
8318 this.editing = false;
8320 this.store.afterReject(this);
8325 * Usually called by the {@link Roo.data.Store} which owns the Record.
8326 * Commits all changes made to the Record since either creation, or the last commit operation.
8328 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8329 * of commit operations.
8331 commit : function(){
8333 delete this.modified;
8334 this.editing = false;
8336 this.store.afterCommit(this);
8341 hasError : function(){
8342 return this.error != null;
8346 clearError : function(){
8351 * Creates a copy of this record.
8352 * @param {String} id (optional) A new record id if you don't want to use this record's id
8355 copy : function(newId) {
8356 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8360 * Ext JS Library 1.1.1
8361 * Copyright(c) 2006-2007, Ext JS, LLC.
8363 * Originally Released Under LGPL - original licence link has changed is not relivant.
8366 * <script type="text/javascript">
8372 * @class Roo.data.Store
8373 * @extends Roo.util.Observable
8374 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8375 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8377 * 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
8378 * has no knowledge of the format of the data returned by the Proxy.<br>
8380 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8381 * instances from the data object. These records are cached and made available through accessor functions.
8383 * Creates a new Store.
8384 * @param {Object} config A config object containing the objects needed for the Store to access data,
8385 * and read the data into Records.
8387 Roo.data.Store = function(config){
8388 this.data = new Roo.util.MixedCollection(false);
8389 this.data.getKey = function(o){
8392 this.baseParams = {};
8399 "multisort" : "_multisort"
8402 if(config && config.data){
8403 this.inlineData = config.data;
8407 Roo.apply(this, config);
8409 if(this.reader){ // reader passed
8410 this.reader = Roo.factory(this.reader, Roo.data);
8411 this.reader.xmodule = this.xmodule || false;
8412 if(!this.recordType){
8413 this.recordType = this.reader.recordType;
8415 if(this.reader.onMetaChange){
8416 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8420 if(this.recordType){
8421 this.fields = this.recordType.prototype.fields;
8427 * @event datachanged
8428 * Fires when the data cache has changed, and a widget which is using this Store
8429 * as a Record cache should refresh its view.
8430 * @param {Store} this
8435 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8436 * @param {Store} this
8437 * @param {Object} meta The JSON metadata
8442 * Fires when Records have been added to the Store
8443 * @param {Store} this
8444 * @param {Roo.data.Record[]} records The array of Records added
8445 * @param {Number} index The index at which the record(s) were added
8450 * Fires when a Record has been removed from the Store
8451 * @param {Store} this
8452 * @param {Roo.data.Record} record The Record that was removed
8453 * @param {Number} index The index at which the record was removed
8458 * Fires when a Record has been updated
8459 * @param {Store} this
8460 * @param {Roo.data.Record} record The Record that was updated
8461 * @param {String} operation The update operation being performed. Value may be one of:
8463 Roo.data.Record.EDIT
8464 Roo.data.Record.REJECT
8465 Roo.data.Record.COMMIT
8471 * Fires when the data cache has been cleared.
8472 * @param {Store} this
8477 * Fires before a request is made for a new data object. If the beforeload handler returns false
8478 * the load action will be canceled.
8479 * @param {Store} this
8480 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8484 * @event beforeloadadd
8485 * Fires after a new set of Records has been loaded.
8486 * @param {Store} this
8487 * @param {Roo.data.Record[]} records The Records that were loaded
8488 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8490 beforeloadadd : true,
8493 * Fires after a new set of Records has been loaded, before they are added to the store.
8494 * @param {Store} this
8495 * @param {Roo.data.Record[]} records The Records that were loaded
8496 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8497 * @params {Object} return from reader
8501 * @event loadexception
8502 * Fires if an exception occurs in the Proxy during loading.
8503 * Called with the signature of the Proxy's "loadexception" event.
8504 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8507 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8508 * @param {Object} load options
8509 * @param {Object} jsonData from your request (normally this contains the Exception)
8511 loadexception : true
8515 this.proxy = Roo.factory(this.proxy, Roo.data);
8516 this.proxy.xmodule = this.xmodule || false;
8517 this.relayEvents(this.proxy, ["loadexception"]);
8519 this.sortToggle = {};
8520 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8522 Roo.data.Store.superclass.constructor.call(this);
8524 if(this.inlineData){
8525 this.loadData(this.inlineData);
8526 delete this.inlineData;
8530 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8532 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8533 * without a remote query - used by combo/forms at present.
8537 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8540 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8543 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8544 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8547 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8548 * on any HTTP request
8551 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8554 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8558 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8559 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8564 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8565 * loaded or when a record is removed. (defaults to false).
8567 pruneModifiedRecords : false,
8573 * Add Records to the Store and fires the add event.
8574 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8576 add : function(records){
8577 records = [].concat(records);
8578 for(var i = 0, len = records.length; i < len; i++){
8579 records[i].join(this);
8581 var index = this.data.length;
8582 this.data.addAll(records);
8583 this.fireEvent("add", this, records, index);
8587 * Remove a Record from the Store and fires the remove event.
8588 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8590 remove : function(record){
8591 var index = this.data.indexOf(record);
8592 this.data.removeAt(index);
8593 if(this.pruneModifiedRecords){
8594 this.modified.remove(record);
8596 this.fireEvent("remove", this, record, index);
8600 * Remove all Records from the Store and fires the clear event.
8602 removeAll : function(){
8604 if(this.pruneModifiedRecords){
8607 this.fireEvent("clear", this);
8611 * Inserts Records to the Store at the given index and fires the add event.
8612 * @param {Number} index The start index at which to insert the passed Records.
8613 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8615 insert : function(index, records){
8616 records = [].concat(records);
8617 for(var i = 0, len = records.length; i < len; i++){
8618 this.data.insert(index, records[i]);
8619 records[i].join(this);
8621 this.fireEvent("add", this, records, index);
8625 * Get the index within the cache of the passed Record.
8626 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8627 * @return {Number} The index of the passed Record. Returns -1 if not found.
8629 indexOf : function(record){
8630 return this.data.indexOf(record);
8634 * Get the index within the cache of the Record with the passed id.
8635 * @param {String} id The id of the Record to find.
8636 * @return {Number} The index of the Record. Returns -1 if not found.
8638 indexOfId : function(id){
8639 return this.data.indexOfKey(id);
8643 * Get the Record with the specified id.
8644 * @param {String} id The id of the Record to find.
8645 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8647 getById : function(id){
8648 return this.data.key(id);
8652 * Get the Record at the specified index.
8653 * @param {Number} index The index of the Record to find.
8654 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8656 getAt : function(index){
8657 return this.data.itemAt(index);
8661 * Returns a range of Records between specified indices.
8662 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8663 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8664 * @return {Roo.data.Record[]} An array of Records
8666 getRange : function(start, end){
8667 return this.data.getRange(start, end);
8671 storeOptions : function(o){
8672 o = Roo.apply({}, o);
8675 this.lastOptions = o;
8679 * Loads the Record cache from the configured Proxy using the configured Reader.
8681 * If using remote paging, then the first load call must specify the <em>start</em>
8682 * and <em>limit</em> properties in the options.params property to establish the initial
8683 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8685 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8686 * and this call will return before the new data has been loaded. Perform any post-processing
8687 * in a callback function, or in a "load" event handler.</strong>
8689 * @param {Object} options An object containing properties which control loading options:<ul>
8690 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8691 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8692 * passed the following arguments:<ul>
8693 * <li>r : Roo.data.Record[]</li>
8694 * <li>options: Options object from the load call</li>
8695 * <li>success: Boolean success indicator</li></ul></li>
8696 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8697 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8700 load : function(options){
8701 options = options || {};
8702 if(this.fireEvent("beforeload", this, options) !== false){
8703 this.storeOptions(options);
8704 var p = Roo.apply(options.params || {}, this.baseParams);
8705 // if meta was not loaded from remote source.. try requesting it.
8706 if (!this.reader.metaFromRemote) {
8709 if(this.sortInfo && this.remoteSort){
8710 var pn = this.paramNames;
8711 p[pn["sort"]] = this.sortInfo.field;
8712 p[pn["dir"]] = this.sortInfo.direction;
8714 if (this.multiSort) {
8715 var pn = this.paramNames;
8716 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8719 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8724 * Reloads the Record cache from the configured Proxy using the configured Reader and
8725 * the options from the last load operation performed.
8726 * @param {Object} options (optional) An object containing properties which may override the options
8727 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8728 * the most recently used options are reused).
8730 reload : function(options){
8731 this.load(Roo.applyIf(options||{}, this.lastOptions));
8735 // Called as a callback by the Reader during a load operation.
8736 loadRecords : function(o, options, success){
8737 if(!o || success === false){
8738 if(success !== false){
8739 this.fireEvent("load", this, [], options, o);
8741 if(options.callback){
8742 options.callback.call(options.scope || this, [], options, false);
8746 // if data returned failure - throw an exception.
8747 if (o.success === false) {
8748 // show a message if no listener is registered.
8749 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8750 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8752 // loadmask wil be hooked into this..
8753 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8756 var r = o.records, t = o.totalRecords || r.length;
8758 this.fireEvent("beforeloadadd", this, r, options, o);
8760 if(!options || options.add !== true){
8761 if(this.pruneModifiedRecords){
8764 for(var i = 0, len = r.length; i < len; i++){
8768 this.data = this.snapshot;
8769 delete this.snapshot;
8772 this.data.addAll(r);
8773 this.totalLength = t;
8775 this.fireEvent("datachanged", this);
8777 this.totalLength = Math.max(t, this.data.length+r.length);
8780 this.fireEvent("load", this, r, options, o);
8781 if(options.callback){
8782 options.callback.call(options.scope || this, r, options, true);
8788 * Loads data from a passed data block. A Reader which understands the format of the data
8789 * must have been configured in the constructor.
8790 * @param {Object} data The data block from which to read the Records. The format of the data expected
8791 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8792 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8794 loadData : function(o, append){
8795 var r = this.reader.readRecords(o);
8796 this.loadRecords(r, {add: append}, true);
8800 * Gets the number of cached records.
8802 * <em>If using paging, this may not be the total size of the dataset. If the data object
8803 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8804 * the data set size</em>
8806 getCount : function(){
8807 return this.data.length || 0;
8811 * Gets the total number of records in the dataset as returned by the server.
8813 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8814 * the dataset size</em>
8816 getTotalCount : function(){
8817 return this.totalLength || 0;
8821 * Returns the sort state of the Store as an object with two properties:
8823 field {String} The name of the field by which the Records are sorted
8824 direction {String} The sort order, "ASC" or "DESC"
8827 getSortState : function(){
8828 return this.sortInfo;
8832 applySort : function(){
8833 if(this.sortInfo && !this.remoteSort){
8834 var s = this.sortInfo, f = s.field;
8835 var st = this.fields.get(f).sortType;
8836 var fn = function(r1, r2){
8837 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8838 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8840 this.data.sort(s.direction, fn);
8841 if(this.snapshot && this.snapshot != this.data){
8842 this.snapshot.sort(s.direction, fn);
8848 * Sets the default sort column and order to be used by the next load operation.
8849 * @param {String} fieldName The name of the field to sort by.
8850 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8852 setDefaultSort : function(field, dir){
8853 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8858 * If remote sorting is used, the sort is performed on the server, and the cache is
8859 * reloaded. If local sorting is used, the cache is sorted internally.
8860 * @param {String} fieldName The name of the field to sort by.
8861 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8863 sort : function(fieldName, dir){
8864 var f = this.fields.get(fieldName);
8866 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8868 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8869 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8874 this.sortToggle[f.name] = dir;
8875 this.sortInfo = {field: f.name, direction: dir};
8876 if(!this.remoteSort){
8878 this.fireEvent("datachanged", this);
8880 this.load(this.lastOptions);
8885 * Calls the specified function for each of the Records in the cache.
8886 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8887 * Returning <em>false</em> aborts and exits the iteration.
8888 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8890 each : function(fn, scope){
8891 this.data.each(fn, scope);
8895 * Gets all records modified since the last commit. Modified records are persisted across load operations
8896 * (e.g., during paging).
8897 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8899 getModifiedRecords : function(){
8900 return this.modified;
8904 createFilterFn : function(property, value, anyMatch){
8905 if(!value.exec){ // not a regex
8906 value = String(value);
8907 if(value.length == 0){
8910 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8913 return value.test(r.data[property]);
8918 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8919 * @param {String} property A field on your records
8920 * @param {Number} start The record index to start at (defaults to 0)
8921 * @param {Number} end The last record index to include (defaults to length - 1)
8922 * @return {Number} The sum
8924 sum : function(property, start, end){
8925 var rs = this.data.items, v = 0;
8927 end = (end || end === 0) ? end : rs.length-1;
8929 for(var i = start; i <= end; i++){
8930 v += (rs[i].data[property] || 0);
8936 * Filter the records by a specified property.
8937 * @param {String} field A field on your records
8938 * @param {String/RegExp} value Either a string that the field
8939 * should start with or a RegExp to test against the field
8940 * @param {Boolean} anyMatch True to match any part not just the beginning
8942 filter : function(property, value, anyMatch){
8943 var fn = this.createFilterFn(property, value, anyMatch);
8944 return fn ? this.filterBy(fn) : this.clearFilter();
8948 * Filter by a function. The specified function will be called with each
8949 * record in this data source. If the function returns true the record is included,
8950 * otherwise it is filtered.
8951 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8952 * @param {Object} scope (optional) The scope of the function (defaults to this)
8954 filterBy : function(fn, scope){
8955 this.snapshot = this.snapshot || this.data;
8956 this.data = this.queryBy(fn, scope||this);
8957 this.fireEvent("datachanged", this);
8961 * Query the records by a specified property.
8962 * @param {String} field A field on your records
8963 * @param {String/RegExp} value Either a string that the field
8964 * should start with or a RegExp to test against the field
8965 * @param {Boolean} anyMatch True to match any part not just the beginning
8966 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8968 query : function(property, value, anyMatch){
8969 var fn = this.createFilterFn(property, value, anyMatch);
8970 return fn ? this.queryBy(fn) : this.data.clone();
8974 * Query by a function. The specified function will be called with each
8975 * record in this data source. If the function returns true the record is included
8977 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8978 * @param {Object} scope (optional) The scope of the function (defaults to this)
8979 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8981 queryBy : function(fn, scope){
8982 var data = this.snapshot || this.data;
8983 return data.filterBy(fn, scope||this);
8987 * Collects unique values for a particular dataIndex from this store.
8988 * @param {String} dataIndex The property to collect
8989 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8990 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8991 * @return {Array} An array of the unique values
8993 collect : function(dataIndex, allowNull, bypassFilter){
8994 var d = (bypassFilter === true && this.snapshot) ?
8995 this.snapshot.items : this.data.items;
8996 var v, sv, r = [], l = {};
8997 for(var i = 0, len = d.length; i < len; i++){
8998 v = d[i].data[dataIndex];
9000 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9009 * Revert to a view of the Record cache with no filtering applied.
9010 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9012 clearFilter : function(suppressEvent){
9013 if(this.snapshot && this.snapshot != this.data){
9014 this.data = this.snapshot;
9015 delete this.snapshot;
9016 if(suppressEvent !== true){
9017 this.fireEvent("datachanged", this);
9023 afterEdit : function(record){
9024 if(this.modified.indexOf(record) == -1){
9025 this.modified.push(record);
9027 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9031 afterReject : function(record){
9032 this.modified.remove(record);
9033 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9037 afterCommit : function(record){
9038 this.modified.remove(record);
9039 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9043 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9044 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9046 commitChanges : function(){
9047 var m = this.modified.slice(0);
9049 for(var i = 0, len = m.length; i < len; i++){
9055 * Cancel outstanding changes on all changed records.
9057 rejectChanges : function(){
9058 var m = this.modified.slice(0);
9060 for(var i = 0, len = m.length; i < len; i++){
9065 onMetaChange : function(meta, rtype, o){
9066 this.recordType = rtype;
9067 this.fields = rtype.prototype.fields;
9068 delete this.snapshot;
9069 this.sortInfo = meta.sortInfo || this.sortInfo;
9071 this.fireEvent('metachange', this, this.reader.meta);
9074 moveIndex : function(data, type)
9076 var index = this.indexOf(data);
9078 var newIndex = index + type;
9082 this.insert(newIndex, data);
9087 * Ext JS Library 1.1.1
9088 * Copyright(c) 2006-2007, Ext JS, LLC.
9090 * Originally Released Under LGPL - original licence link has changed is not relivant.
9093 * <script type="text/javascript">
9097 * @class Roo.data.SimpleStore
9098 * @extends Roo.data.Store
9099 * Small helper class to make creating Stores from Array data easier.
9100 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9101 * @cfg {Array} fields An array of field definition objects, or field name strings.
9102 * @cfg {Array} data The multi-dimensional array of data
9104 * @param {Object} config
9106 Roo.data.SimpleStore = function(config){
9107 Roo.data.SimpleStore.superclass.constructor.call(this, {
9109 reader: new Roo.data.ArrayReader({
9112 Roo.data.Record.create(config.fields)
9114 proxy : new Roo.data.MemoryProxy(config.data)
9118 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9120 * Ext JS Library 1.1.1
9121 * Copyright(c) 2006-2007, Ext JS, LLC.
9123 * Originally Released Under LGPL - original licence link has changed is not relivant.
9126 * <script type="text/javascript">
9131 * @extends Roo.data.Store
9132 * @class Roo.data.JsonStore
9133 * Small helper class to make creating Stores for JSON data easier. <br/>
9135 var store = new Roo.data.JsonStore({
9136 url: 'get-images.php',
9138 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9141 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9142 * JsonReader and HttpProxy (unless inline data is provided).</b>
9143 * @cfg {Array} fields An array of field definition objects, or field name strings.
9145 * @param {Object} config
9147 Roo.data.JsonStore = function(c){
9148 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9149 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9150 reader: new Roo.data.JsonReader(c, c.fields)
9153 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9155 * Ext JS Library 1.1.1
9156 * Copyright(c) 2006-2007, Ext JS, LLC.
9158 * Originally Released Under LGPL - original licence link has changed is not relivant.
9161 * <script type="text/javascript">
9165 Roo.data.Field = function(config){
9166 if(typeof config == "string"){
9167 config = {name: config};
9169 Roo.apply(this, config);
9175 var st = Roo.data.SortTypes;
9176 // named sortTypes are supported, here we look them up
9177 if(typeof this.sortType == "string"){
9178 this.sortType = st[this.sortType];
9181 // set default sortType for strings and dates
9185 this.sortType = st.asUCString;
9188 this.sortType = st.asDate;
9191 this.sortType = st.none;
9196 var stripRe = /[\$,%]/g;
9198 // prebuilt conversion function for this field, instead of
9199 // switching every time we're reading a value
9201 var cv, dateFormat = this.dateFormat;
9206 cv = function(v){ return v; };
9209 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9213 return v !== undefined && v !== null && v !== '' ?
9214 parseInt(String(v).replace(stripRe, ""), 10) : '';
9219 return v !== undefined && v !== null && v !== '' ?
9220 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9225 cv = function(v){ return v === true || v === "true" || v == 1; };
9232 if(v instanceof Date){
9236 if(dateFormat == "timestamp"){
9237 return new Date(v*1000);
9239 return Date.parseDate(v, dateFormat);
9241 var parsed = Date.parse(v);
9242 return parsed ? new Date(parsed) : null;
9251 Roo.data.Field.prototype = {
9259 * Ext JS Library 1.1.1
9260 * Copyright(c) 2006-2007, Ext JS, LLC.
9262 * Originally Released Under LGPL - original licence link has changed is not relivant.
9265 * <script type="text/javascript">
9268 // Base class for reading structured data from a data source. This class is intended to be
9269 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9272 * @class Roo.data.DataReader
9273 * Base class for reading structured data from a data source. This class is intended to be
9274 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9277 Roo.data.DataReader = function(meta, recordType){
9281 this.recordType = recordType instanceof Array ?
9282 Roo.data.Record.create(recordType) : recordType;
9285 Roo.data.DataReader.prototype = {
9287 * Create an empty record
9288 * @param {Object} data (optional) - overlay some values
9289 * @return {Roo.data.Record} record created.
9291 newRow : function(d) {
9293 this.recordType.prototype.fields.each(function(c) {
9295 case 'int' : da[c.name] = 0; break;
9296 case 'date' : da[c.name] = new Date(); break;
9297 case 'float' : da[c.name] = 0.0; break;
9298 case 'boolean' : da[c.name] = false; break;
9299 default : da[c.name] = ""; break;
9303 return new this.recordType(Roo.apply(da, d));
9308 * Ext JS Library 1.1.1
9309 * Copyright(c) 2006-2007, Ext JS, LLC.
9311 * Originally Released Under LGPL - original licence link has changed is not relivant.
9314 * <script type="text/javascript">
9318 * @class Roo.data.DataProxy
9319 * @extends Roo.data.Observable
9320 * This class is an abstract base class for implementations which provide retrieval of
9321 * unformatted data objects.<br>
9323 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9324 * (of the appropriate type which knows how to parse the data object) to provide a block of
9325 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9327 * Custom implementations must implement the load method as described in
9328 * {@link Roo.data.HttpProxy#load}.
9330 Roo.data.DataProxy = function(){
9334 * Fires before a network request is made to retrieve a data object.
9335 * @param {Object} This DataProxy object.
9336 * @param {Object} params The params parameter to the load function.
9341 * Fires before the load method's callback is called.
9342 * @param {Object} This DataProxy object.
9343 * @param {Object} o The data object.
9344 * @param {Object} arg The callback argument object passed to the load function.
9348 * @event loadexception
9349 * Fires if an Exception occurs during data retrieval.
9350 * @param {Object} This DataProxy object.
9351 * @param {Object} o The data object.
9352 * @param {Object} arg The callback argument object passed to the load function.
9353 * @param {Object} e The Exception.
9355 loadexception : true
9357 Roo.data.DataProxy.superclass.constructor.call(this);
9360 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9363 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9367 * Ext JS Library 1.1.1
9368 * Copyright(c) 2006-2007, Ext JS, LLC.
9370 * Originally Released Under LGPL - original licence link has changed is not relivant.
9373 * <script type="text/javascript">
9376 * @class Roo.data.MemoryProxy
9377 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9378 * to the Reader when its load method is called.
9380 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9382 Roo.data.MemoryProxy = function(data){
9386 Roo.data.MemoryProxy.superclass.constructor.call(this);
9390 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9392 * Load data from the requested source (in this case an in-memory
9393 * data object passed to the constructor), read the data object into
9394 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9395 * process that block using the passed callback.
9396 * @param {Object} params This parameter is not used by the MemoryProxy class.
9397 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9398 * object into a block of Roo.data.Records.
9399 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9400 * The function must be passed <ul>
9401 * <li>The Record block object</li>
9402 * <li>The "arg" argument from the load function</li>
9403 * <li>A boolean success indicator</li>
9405 * @param {Object} scope The scope in which to call the callback
9406 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9408 load : function(params, reader, callback, scope, arg){
9409 params = params || {};
9412 result = reader.readRecords(this.data);
9414 this.fireEvent("loadexception", this, arg, null, e);
9415 callback.call(scope, null, arg, false);
9418 callback.call(scope, result, arg, true);
9422 update : function(params, records){
9427 * Ext JS Library 1.1.1
9428 * Copyright(c) 2006-2007, Ext JS, LLC.
9430 * Originally Released Under LGPL - original licence link has changed is not relivant.
9433 * <script type="text/javascript">
9436 * @class Roo.data.HttpProxy
9437 * @extends Roo.data.DataProxy
9438 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9439 * configured to reference a certain URL.<br><br>
9441 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9442 * from which the running page was served.<br><br>
9444 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9446 * Be aware that to enable the browser to parse an XML document, the server must set
9447 * the Content-Type header in the HTTP response to "text/xml".
9449 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9450 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9451 * will be used to make the request.
9453 Roo.data.HttpProxy = function(conn){
9454 Roo.data.HttpProxy.superclass.constructor.call(this);
9455 // is conn a conn config or a real conn?
9457 this.useAjax = !conn || !conn.events;
9461 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9462 // thse are take from connection...
9465 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9468 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9469 * extra parameters to each request made by this object. (defaults to undefined)
9472 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9473 * to each request made by this object. (defaults to undefined)
9476 * @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)
9479 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9482 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9488 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9492 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9493 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9494 * a finer-grained basis than the DataProxy events.
9496 getConnection : function(){
9497 return this.useAjax ? Roo.Ajax : this.conn;
9501 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9502 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9503 * process that block using the passed callback.
9504 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9505 * for the request to the remote server.
9506 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9507 * object into a block of Roo.data.Records.
9508 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9509 * The function must be passed <ul>
9510 * <li>The Record block object</li>
9511 * <li>The "arg" argument from the load function</li>
9512 * <li>A boolean success indicator</li>
9514 * @param {Object} scope The scope in which to call the callback
9515 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9517 load : function(params, reader, callback, scope, arg){
9518 if(this.fireEvent("beforeload", this, params) !== false){
9520 params : params || {},
9522 callback : callback,
9527 callback : this.loadResponse,
9531 Roo.applyIf(o, this.conn);
9532 if(this.activeRequest){
9533 Roo.Ajax.abort(this.activeRequest);
9535 this.activeRequest = Roo.Ajax.request(o);
9537 this.conn.request(o);
9540 callback.call(scope||this, null, arg, false);
9545 loadResponse : function(o, success, response){
9546 delete this.activeRequest;
9548 this.fireEvent("loadexception", this, o, response);
9549 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9554 result = o.reader.read(response);
9556 this.fireEvent("loadexception", this, o, response, e);
9557 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9561 this.fireEvent("load", this, o, o.request.arg);
9562 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9566 update : function(dataSet){
9571 updateResponse : function(dataSet){
9576 * Ext JS Library 1.1.1
9577 * Copyright(c) 2006-2007, Ext JS, LLC.
9579 * Originally Released Under LGPL - original licence link has changed is not relivant.
9582 * <script type="text/javascript">
9586 * @class Roo.data.ScriptTagProxy
9587 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9588 * other than the originating domain of the running page.<br><br>
9590 * <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
9591 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9593 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9594 * source code that is used as the source inside a <script> tag.<br><br>
9596 * In order for the browser to process the returned data, the server must wrap the data object
9597 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9598 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9599 * depending on whether the callback name was passed:
9602 boolean scriptTag = false;
9603 String cb = request.getParameter("callback");
9606 response.setContentType("text/javascript");
9608 response.setContentType("application/x-json");
9610 Writer out = response.getWriter();
9612 out.write(cb + "(");
9614 out.print(dataBlock.toJsonString());
9621 * @param {Object} config A configuration object.
9623 Roo.data.ScriptTagProxy = function(config){
9624 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9625 Roo.apply(this, config);
9626 this.head = document.getElementsByTagName("head")[0];
9629 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9631 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9633 * @cfg {String} url The URL from which to request the data object.
9636 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9640 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9641 * the server the name of the callback function set up by the load call to process the returned data object.
9642 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9643 * javascript output which calls this named function passing the data object as its only parameter.
9645 callbackParam : "callback",
9647 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9648 * name to the request.
9653 * Load data from the configured URL, read the data object into
9654 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9655 * process that block using the passed callback.
9656 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9657 * for the request to the remote server.
9658 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9659 * object into a block of Roo.data.Records.
9660 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9661 * The function must be passed <ul>
9662 * <li>The Record block object</li>
9663 * <li>The "arg" argument from the load function</li>
9664 * <li>A boolean success indicator</li>
9666 * @param {Object} scope The scope in which to call the callback
9667 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9669 load : function(params, reader, callback, scope, arg){
9670 if(this.fireEvent("beforeload", this, params) !== false){
9672 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9675 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9677 url += "&_dc=" + (new Date().getTime());
9679 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9682 cb : "stcCallback"+transId,
9683 scriptId : "stcScript"+transId,
9687 callback : callback,
9693 window[trans.cb] = function(o){
9694 conn.handleResponse(o, trans);
9697 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9699 if(this.autoAbort !== false){
9703 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9705 var script = document.createElement("script");
9706 script.setAttribute("src", url);
9707 script.setAttribute("type", "text/javascript");
9708 script.setAttribute("id", trans.scriptId);
9709 this.head.appendChild(script);
9713 callback.call(scope||this, null, arg, false);
9718 isLoading : function(){
9719 return this.trans ? true : false;
9723 * Abort the current server request.
9726 if(this.isLoading()){
9727 this.destroyTrans(this.trans);
9732 destroyTrans : function(trans, isLoaded){
9733 this.head.removeChild(document.getElementById(trans.scriptId));
9734 clearTimeout(trans.timeoutId);
9736 window[trans.cb] = undefined;
9738 delete window[trans.cb];
9741 // if hasn't been loaded, wait for load to remove it to prevent script error
9742 window[trans.cb] = function(){
9743 window[trans.cb] = undefined;
9745 delete window[trans.cb];
9752 handleResponse : function(o, trans){
9754 this.destroyTrans(trans, true);
9757 result = trans.reader.readRecords(o);
9759 this.fireEvent("loadexception", this, o, trans.arg, e);
9760 trans.callback.call(trans.scope||window, null, trans.arg, false);
9763 this.fireEvent("load", this, o, trans.arg);
9764 trans.callback.call(trans.scope||window, result, trans.arg, true);
9768 handleFailure : function(trans){
9770 this.destroyTrans(trans, false);
9771 this.fireEvent("loadexception", this, null, trans.arg);
9772 trans.callback.call(trans.scope||window, null, trans.arg, false);
9776 * Ext JS Library 1.1.1
9777 * Copyright(c) 2006-2007, Ext JS, LLC.
9779 * Originally Released Under LGPL - original licence link has changed is not relivant.
9782 * <script type="text/javascript">
9786 * @class Roo.data.JsonReader
9787 * @extends Roo.data.DataReader
9788 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9789 * based on mappings in a provided Roo.data.Record constructor.
9791 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9792 * in the reply previously.
9797 var RecordDef = Roo.data.Record.create([
9798 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9799 {name: 'occupation'} // This field will use "occupation" as the mapping.
9801 var myReader = new Roo.data.JsonReader({
9802 totalProperty: "results", // The property which contains the total dataset size (optional)
9803 root: "rows", // The property which contains an Array of row objects
9804 id: "id" // The property within each row object that provides an ID for the record (optional)
9808 * This would consume a JSON file like this:
9810 { 'results': 2, 'rows': [
9811 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9812 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9815 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9816 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9817 * paged from the remote server.
9818 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9819 * @cfg {String} root name of the property which contains the Array of row objects.
9820 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9822 * Create a new JsonReader
9823 * @param {Object} meta Metadata configuration options
9824 * @param {Object} recordType Either an Array of field definition objects,
9825 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9827 Roo.data.JsonReader = function(meta, recordType){
9830 // set some defaults:
9832 totalProperty: 'total',
9833 successProperty : 'success',
9838 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9840 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9843 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9844 * Used by Store query builder to append _requestMeta to params.
9847 metaFromRemote : false,
9849 * This method is only used by a DataProxy which has retrieved data from a remote server.
9850 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9851 * @return {Object} data A data block which is used by an Roo.data.Store object as
9852 * a cache of Roo.data.Records.
9854 read : function(response){
9855 var json = response.responseText;
9857 var o = /* eval:var:o */ eval("("+json+")");
9859 throw {message: "JsonReader.read: Json object not found"};
9865 this.metaFromRemote = true;
9866 this.meta = o.metaData;
9867 this.recordType = Roo.data.Record.create(o.metaData.fields);
9868 this.onMetaChange(this.meta, this.recordType, o);
9870 return this.readRecords(o);
9873 // private function a store will implement
9874 onMetaChange : function(meta, recordType, o){
9881 simpleAccess: function(obj, subsc) {
9888 getJsonAccessor: function(){
9890 return function(expr) {
9892 return(re.test(expr))
9893 ? new Function("obj", "return obj." + expr)
9903 * Create a data block containing Roo.data.Records from an XML document.
9904 * @param {Object} o An object which contains an Array of row objects in the property specified
9905 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9906 * which contains the total size of the dataset.
9907 * @return {Object} data A data block which is used by an Roo.data.Store object as
9908 * a cache of Roo.data.Records.
9910 readRecords : function(o){
9912 * After any data loads, the raw JSON data is available for further custom processing.
9916 var s = this.meta, Record = this.recordType,
9917 f = Record.prototype.fields, fi = f.items, fl = f.length;
9919 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9921 if(s.totalProperty) {
9922 this.getTotal = this.getJsonAccessor(s.totalProperty);
9924 if(s.successProperty) {
9925 this.getSuccess = this.getJsonAccessor(s.successProperty);
9927 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9929 var g = this.getJsonAccessor(s.id);
9930 this.getId = function(rec) {
9932 return (r === undefined || r === "") ? null : r;
9935 this.getId = function(){return null;};
9938 for(var jj = 0; jj < fl; jj++){
9940 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9941 this.ef[jj] = this.getJsonAccessor(map);
9945 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9946 if(s.totalProperty){
9947 var vt = parseInt(this.getTotal(o), 10);
9952 if(s.successProperty){
9953 var vs = this.getSuccess(o);
9954 if(vs === false || vs === 'false'){
9959 for(var i = 0; i < c; i++){
9962 var id = this.getId(n);
9963 for(var j = 0; j < fl; j++){
9965 var v = this.ef[j](n);
9967 Roo.log('missing convert for ' + f.name);
9971 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9973 var record = new Record(values, id);
9975 records[i] = record;
9981 totalRecords : totalRecords
9986 * Ext JS Library 1.1.1
9987 * Copyright(c) 2006-2007, Ext JS, LLC.
9989 * Originally Released Under LGPL - original licence link has changed is not relivant.
9992 * <script type="text/javascript">
9996 * @class Roo.data.ArrayReader
9997 * @extends Roo.data.DataReader
9998 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9999 * Each element of that Array represents a row of data fields. The
10000 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10001 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10005 var RecordDef = Roo.data.Record.create([
10006 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10007 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10009 var myReader = new Roo.data.ArrayReader({
10010 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10014 * This would consume an Array like this:
10016 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10018 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10020 * Create a new JsonReader
10021 * @param {Object} meta Metadata configuration options.
10022 * @param {Object} recordType Either an Array of field definition objects
10023 * as specified to {@link Roo.data.Record#create},
10024 * or an {@link Roo.data.Record} object
10025 * created using {@link Roo.data.Record#create}.
10027 Roo.data.ArrayReader = function(meta, recordType){
10028 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10031 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10033 * Create a data block containing Roo.data.Records from an XML document.
10034 * @param {Object} o An Array of row objects which represents the dataset.
10035 * @return {Object} data A data block which is used by an Roo.data.Store object as
10036 * a cache of Roo.data.Records.
10038 readRecords : function(o){
10039 var sid = this.meta ? this.meta.id : null;
10040 var recordType = this.recordType, fields = recordType.prototype.fields;
10043 for(var i = 0; i < root.length; i++){
10046 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10047 for(var j = 0, jlen = fields.length; j < jlen; j++){
10048 var f = fields.items[j];
10049 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10050 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10052 values[f.name] = v;
10054 var record = new recordType(values, id);
10056 records[records.length] = record;
10060 totalRecords : records.length
10069 * @class Roo.bootstrap.ComboBox
10070 * @extends Roo.bootstrap.TriggerField
10071 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10072 * @cfg {Boolean} append (true|false) default false
10073 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10074 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10075 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10076 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10078 * Create a new ComboBox.
10079 * @param {Object} config Configuration options
10081 Roo.bootstrap.ComboBox = function(config){
10082 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10086 * Fires when the dropdown list is expanded
10087 * @param {Roo.bootstrap.ComboBox} combo This combo box
10092 * Fires when the dropdown list is collapsed
10093 * @param {Roo.bootstrap.ComboBox} combo This combo box
10097 * @event beforeselect
10098 * Fires before a list item is selected. Return false to cancel the selection.
10099 * @param {Roo.bootstrap.ComboBox} combo This combo box
10100 * @param {Roo.data.Record} record The data record returned from the underlying store
10101 * @param {Number} index The index of the selected item in the dropdown list
10103 'beforeselect' : true,
10106 * Fires when a list item is selected
10107 * @param {Roo.bootstrap.ComboBox} combo This combo box
10108 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10109 * @param {Number} index The index of the selected item in the dropdown list
10113 * @event beforequery
10114 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10115 * The event object passed has these properties:
10116 * @param {Roo.bootstrap.ComboBox} combo This combo box
10117 * @param {String} query The query
10118 * @param {Boolean} forceAll true to force "all" query
10119 * @param {Boolean} cancel true to cancel the query
10120 * @param {Object} e The query event object
10122 'beforequery': true,
10125 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10126 * @param {Roo.bootstrap.ComboBox} combo This combo box
10131 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10132 * @param {Roo.bootstrap.ComboBox} combo This combo box
10133 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10138 * Fires when the remove value from the combobox array
10139 * @param {Roo.bootstrap.ComboBox} combo This combo box
10146 this.tickItems = [];
10148 this.selectedIndex = -1;
10149 if(this.mode == 'local'){
10150 if(config.queryDelay === undefined){
10151 this.queryDelay = 10;
10153 if(config.minChars === undefined){
10159 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10162 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10163 * rendering into an Roo.Editor, defaults to false)
10166 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10167 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10170 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10173 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10174 * the dropdown list (defaults to undefined, with no header element)
10178 * @cfg {String/Roo.Template} tpl The template to use to render the output
10182 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10184 listWidth: undefined,
10186 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10187 * mode = 'remote' or 'text' if mode = 'local')
10189 displayField: undefined,
10191 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10192 * mode = 'remote' or 'value' if mode = 'local').
10193 * Note: use of a valueField requires the user make a selection
10194 * in order for a value to be mapped.
10196 valueField: undefined,
10200 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10201 * field's data value (defaults to the underlying DOM element's name)
10203 hiddenName: undefined,
10205 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10209 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10211 selectedClass: 'active',
10214 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10218 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10219 * anchor positions (defaults to 'tl-bl')
10221 listAlign: 'tl-bl?',
10223 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10227 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10228 * query specified by the allQuery config option (defaults to 'query')
10230 triggerAction: 'query',
10232 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10233 * (defaults to 4, does not apply if editable = false)
10237 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10238 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10242 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10243 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10247 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10248 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10252 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10253 * when editable = true (defaults to false)
10255 selectOnFocus:false,
10257 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10259 queryParam: 'query',
10261 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10262 * when mode = 'remote' (defaults to 'Loading...')
10264 loadingText: 'Loading...',
10266 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10270 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10274 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10275 * traditional select (defaults to true)
10279 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10283 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10287 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10288 * listWidth has a higher value)
10292 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10293 * allow the user to set arbitrary text into the field (defaults to false)
10295 forceSelection:false,
10297 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10298 * if typeAhead = true (defaults to 250)
10300 typeAheadDelay : 250,
10302 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10303 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10305 valueNotFoundText : undefined,
10307 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10309 blockFocus : false,
10312 * @cfg {Boolean} disableClear Disable showing of clear button.
10314 disableClear : false,
10316 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10318 alwaysQuery : false,
10321 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10335 btnPosition : 'right',
10336 triggerList : true,
10337 // element that contains real text value.. (when hidden is used..)
10339 getAutoCreate : function()
10346 if(!this.tickable){
10347 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10352 * ComboBox with tickable selections
10355 var align = this.labelAlign || this.parentLabelAlign();
10358 cls : 'form-group roo-combobox-tickable' //input-group
10364 cls : 'tickable-buttons',
10369 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10376 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10383 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10390 Roo.each(buttons.cn, function(c){
10392 c.cls += ' btn-' + _this.size;
10395 if (_this.disabled) {
10406 cls: 'form-hidden-field'
10410 cls: 'select2-choices',
10414 cls: 'select2-search-field',
10426 cls: 'select2-container input-group select2-container-multi',
10431 // cls: 'typeahead typeahead-long dropdown-menu',
10432 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10437 if (align ==='left' && this.fieldLabel.length) {
10439 Roo.log("left and has label");
10445 cls : 'control-label col-sm-' + this.labelWidth,
10446 html : this.fieldLabel
10450 cls : "col-sm-" + (12 - this.labelWidth),
10457 } else if ( this.fieldLabel.length) {
10463 //cls : 'input-group-addon',
10464 html : this.fieldLabel
10474 Roo.log(" no label && no align");
10481 ['xs','sm','md','lg'].map(function(size){
10482 if (settings[size]) {
10483 cfg.cls += ' col-' + size + '-' + settings[size];
10492 initEvents: function()
10496 throw "can not find store for combo";
10498 this.store = Roo.factory(this.store, Roo.data);
10501 this.initTickableEvnets();
10505 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10507 if(this.hiddenName){
10509 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10511 this.hiddenField.dom.value =
10512 this.hiddenValue !== undefined ? this.hiddenValue :
10513 this.value !== undefined ? this.value : '';
10515 // prevent input submission
10516 this.el.dom.removeAttribute('name');
10517 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10522 // this.el.dom.setAttribute('autocomplete', 'off');
10525 var cls = 'x-combo-list';
10527 //this.list = new Roo.Layer({
10528 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10534 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10535 _this.list.setWidth(lw);
10538 this.list.on('mouseover', this.onViewOver, this);
10539 this.list.on('mousemove', this.onViewMove, this);
10541 this.list.on('scroll', this.onViewScroll, this);
10544 this.list.swallowEvent('mousewheel');
10545 this.assetHeight = 0;
10548 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10549 this.assetHeight += this.header.getHeight();
10552 this.innerList = this.list.createChild({cls:cls+'-inner'});
10553 this.innerList.on('mouseover', this.onViewOver, this);
10554 this.innerList.on('mousemove', this.onViewMove, this);
10555 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10557 if(this.allowBlank && !this.pageSize && !this.disableClear){
10558 this.footer = this.list.createChild({cls:cls+'-ft'});
10559 this.pageTb = new Roo.Toolbar(this.footer);
10563 this.footer = this.list.createChild({cls:cls+'-ft'});
10564 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10565 {pageSize: this.pageSize});
10569 if (this.pageTb && this.allowBlank && !this.disableClear) {
10571 this.pageTb.add(new Roo.Toolbar.Fill(), {
10572 cls: 'x-btn-icon x-btn-clear',
10574 handler: function()
10577 _this.clearValue();
10578 _this.onSelect(false, -1);
10583 this.assetHeight += this.footer.getHeight();
10588 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10591 this.view = new Roo.View(this.list, this.tpl, {
10592 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10594 //this.view.wrapEl.setDisplayed(false);
10595 this.view.on('click', this.onViewClick, this);
10599 this.store.on('beforeload', this.onBeforeLoad, this);
10600 this.store.on('load', this.onLoad, this);
10601 this.store.on('loadexception', this.onLoadException, this);
10603 if(this.resizable){
10604 this.resizer = new Roo.Resizable(this.list, {
10605 pinned:true, handles:'se'
10607 this.resizer.on('resize', function(r, w, h){
10608 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10609 this.listWidth = w;
10610 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10611 this.restrictHeight();
10613 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10616 if(!this.editable){
10617 this.editable = true;
10618 this.setEditable(false);
10623 if (typeof(this.events.add.listeners) != 'undefined') {
10625 this.addicon = this.wrap.createChild(
10626 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10628 this.addicon.on('click', function(e) {
10629 this.fireEvent('add', this);
10632 if (typeof(this.events.edit.listeners) != 'undefined') {
10634 this.editicon = this.wrap.createChild(
10635 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10636 if (this.addicon) {
10637 this.editicon.setStyle('margin-left', '40px');
10639 this.editicon.on('click', function(e) {
10641 // we fire even if inothing is selected..
10642 this.fireEvent('edit', this, this.lastData );
10648 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10649 "up" : function(e){
10650 this.inKeyMode = true;
10654 "down" : function(e){
10655 if(!this.isExpanded()){
10656 this.onTriggerClick();
10658 this.inKeyMode = true;
10663 "enter" : function(e){
10664 // this.onViewClick();
10668 if(this.fireEvent("specialkey", this, e)){
10669 this.onViewClick(false);
10675 "esc" : function(e){
10679 "tab" : function(e){
10682 if(this.fireEvent("specialkey", this, e)){
10683 this.onViewClick(false);
10691 doRelay : function(foo, bar, hname){
10692 if(hname == 'down' || this.scope.isExpanded()){
10693 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10702 this.queryDelay = Math.max(this.queryDelay || 10,
10703 this.mode == 'local' ? 10 : 250);
10706 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10708 if(this.typeAhead){
10709 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10711 if(this.editable !== false){
10712 this.inputEl().on("keyup", this.onKeyUp, this);
10714 if(this.forceSelection){
10715 this.inputEl().on('blur', this.doForce, this);
10719 this.choices = this.el.select('ul.select2-choices', true).first();
10720 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10724 initTickableEvnets: function()
10728 if(this.hiddenName){
10730 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10732 this.hiddenField.dom.value =
10733 this.hiddenValue !== undefined ? this.hiddenValue :
10734 this.value !== undefined ? this.value : '';
10736 // prevent input submission
10737 this.el.dom.removeAttribute('name');
10738 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10743 // this.list = this.el.select('ul.dropdown-menu',true).first();
10745 this.choices = this.el.select('ul.select2-choices', true).first();
10746 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10747 if(this.triggerList){
10748 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10751 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10752 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10754 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10755 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10757 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10758 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10760 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10761 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10762 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10765 this.cancelBtn.hide();
10770 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10771 _this.list.setWidth(lw);
10774 this.list.on('mouseover', this.onViewOver, this);
10775 this.list.on('mousemove', this.onViewMove, this);
10777 this.list.on('scroll', this.onViewScroll, this);
10780 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>';
10783 this.view = new Roo.View(this.list, this.tpl, {
10784 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10787 //this.view.wrapEl.setDisplayed(false);
10788 this.view.on('click', this.onViewClick, this);
10792 this.store.on('beforeload', this.onBeforeLoad, this);
10793 this.store.on('load', this.onLoad, this);
10794 this.store.on('loadexception', this.onLoadException, this);
10796 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10797 // "up" : function(e){
10798 // this.inKeyMode = true;
10799 // this.selectPrev();
10802 // "down" : function(e){
10803 // if(!this.isExpanded()){
10804 // this.onTriggerClick();
10806 // this.inKeyMode = true;
10807 // this.selectNext();
10811 // "enter" : function(e){
10812 //// this.onViewClick();
10814 // this.collapse();
10816 // if(this.fireEvent("specialkey", this, e)){
10817 // this.onViewClick(false);
10823 // "esc" : function(e){
10824 // this.collapse();
10827 // "tab" : function(e){
10828 // this.collapse();
10830 // if(this.fireEvent("specialkey", this, e)){
10831 // this.onViewClick(false);
10839 // doRelay : function(foo, bar, hname){
10840 // if(hname == 'down' || this.scope.isExpanded()){
10841 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10846 // forceKeyDown: true
10850 this.queryDelay = Math.max(this.queryDelay || 10,
10851 this.mode == 'local' ? 10 : 250);
10854 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10856 if(this.typeAhead){
10857 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10861 onDestroy : function(){
10863 this.view.setStore(null);
10864 this.view.el.removeAllListeners();
10865 this.view.el.remove();
10866 this.view.purgeListeners();
10869 this.list.dom.innerHTML = '';
10873 this.store.un('beforeload', this.onBeforeLoad, this);
10874 this.store.un('load', this.onLoad, this);
10875 this.store.un('loadexception', this.onLoadException, this);
10877 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10881 fireKey : function(e){
10882 if(e.isNavKeyPress() && !this.list.isVisible()){
10883 this.fireEvent("specialkey", this, e);
10888 onResize: function(w, h){
10889 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10891 // if(typeof w != 'number'){
10892 // // we do not handle it!?!?
10895 // var tw = this.trigger.getWidth();
10896 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10897 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10899 // this.inputEl().setWidth( this.adjustWidth('input', x));
10901 // //this.trigger.setStyle('left', x+'px');
10903 // if(this.list && this.listWidth === undefined){
10904 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10905 // this.list.setWidth(lw);
10906 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10914 * Allow or prevent the user from directly editing the field text. If false is passed,
10915 * the user will only be able to select from the items defined in the dropdown list. This method
10916 * is the runtime equivalent of setting the 'editable' config option at config time.
10917 * @param {Boolean} value True to allow the user to directly edit the field text
10919 setEditable : function(value){
10920 if(value == this.editable){
10923 this.editable = value;
10925 this.inputEl().dom.setAttribute('readOnly', true);
10926 this.inputEl().on('mousedown', this.onTriggerClick, this);
10927 this.inputEl().addClass('x-combo-noedit');
10929 this.inputEl().dom.setAttribute('readOnly', false);
10930 this.inputEl().un('mousedown', this.onTriggerClick, this);
10931 this.inputEl().removeClass('x-combo-noedit');
10937 onBeforeLoad : function(combo,opts){
10938 if(!this.hasFocus){
10942 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10944 // this.restrictHeight();
10945 this.selectedIndex = -1;
10949 onLoad : function(){
10951 this.hasQuery = false;
10953 if(!this.hasFocus){
10957 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10958 this.loading.hide();
10961 if(this.store.getCount() > 0){
10963 // this.restrictHeight();
10964 if(this.lastQuery == this.allQuery){
10965 if(this.editable && !this.tickable){
10966 this.inputEl().dom.select();
10968 if(!this.selectByValue(this.value, true) && this.autoFocus){
10969 this.select(0, true);
10972 if(this.autoFocus){
10975 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10976 this.taTask.delay(this.typeAheadDelay);
10980 this.onEmptyResults();
10986 onLoadException : function()
10988 this.hasQuery = false;
10990 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10991 this.loading.hide();
10995 Roo.log(this.store.reader.jsonData);
10996 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10998 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11004 onTypeAhead : function(){
11005 if(this.store.getCount() > 0){
11006 var r = this.store.getAt(0);
11007 var newValue = r.data[this.displayField];
11008 var len = newValue.length;
11009 var selStart = this.getRawValue().length;
11011 if(selStart != len){
11012 this.setRawValue(newValue);
11013 this.selectText(selStart, newValue.length);
11019 onSelect : function(record, index){
11021 if(this.fireEvent('beforeselect', this, record, index) !== false){
11023 this.setFromData(index > -1 ? record.data : false);
11026 this.fireEvent('select', this, record, index);
11031 * Returns the currently selected field value or empty string if no value is set.
11032 * @return {String} value The selected value
11034 getValue : function(){
11037 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11040 if(this.valueField){
11041 return typeof this.value != 'undefined' ? this.value : '';
11043 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11048 * Clears any text/value currently set in the field
11050 clearValue : function(){
11051 if(this.hiddenField){
11052 this.hiddenField.dom.value = '';
11055 this.setRawValue('');
11056 this.lastSelectionText = '';
11061 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11062 * will be displayed in the field. If the value does not match the data value of an existing item,
11063 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11064 * Otherwise the field will be blank (although the value will still be set).
11065 * @param {String} value The value to match
11067 setValue : function(v){
11074 if(this.valueField){
11075 var r = this.findRecord(this.valueField, v);
11077 text = r.data[this.displayField];
11078 }else if(this.valueNotFoundText !== undefined){
11079 text = this.valueNotFoundText;
11082 this.lastSelectionText = text;
11083 if(this.hiddenField){
11084 this.hiddenField.dom.value = v;
11086 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11090 * @property {Object} the last set data for the element
11095 * Sets the value of the field based on a object which is related to the record format for the store.
11096 * @param {Object} value the value to set as. or false on reset?
11098 setFromData : function(o){
11105 var dv = ''; // display value
11106 var vv = ''; // value value..
11108 if (this.displayField) {
11109 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11111 // this is an error condition!!!
11112 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11115 if(this.valueField){
11116 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11119 if(this.hiddenField){
11120 this.hiddenField.dom.value = vv;
11122 this.lastSelectionText = dv;
11123 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11127 // no hidden field.. - we store the value in 'value', but still display
11128 // display field!!!!
11129 this.lastSelectionText = dv;
11130 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11136 reset : function(){
11137 // overridden so that last data is reset..
11138 this.setValue(this.originalValue);
11139 this.clearInvalid();
11140 this.lastData = false;
11142 this.view.clearSelections();
11146 findRecord : function(prop, value){
11148 if(this.store.getCount() > 0){
11149 this.store.each(function(r){
11150 if(r.data[prop] == value){
11160 getName: function()
11162 // returns hidden if it's set..
11163 if (!this.rendered) {return ''};
11164 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11168 onViewMove : function(e, t){
11169 this.inKeyMode = false;
11173 onViewOver : function(e, t){
11174 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11177 var item = this.view.findItemFromChild(t);
11180 var index = this.view.indexOf(item);
11181 this.select(index, false);
11186 onViewClick : function(view, doFocus, el, e)
11188 var index = this.view.getSelectedIndexes()[0];
11190 var r = this.store.getAt(index);
11194 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11201 Roo.each(this.tickItems, function(v,k){
11203 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11204 _this.tickItems.splice(k, 1);
11214 this.tickItems.push(r.data);
11219 this.onSelect(r, index);
11221 if(doFocus !== false && !this.blockFocus){
11222 this.inputEl().focus();
11227 restrictHeight : function(){
11228 //this.innerList.dom.style.height = '';
11229 //var inner = this.innerList.dom;
11230 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11231 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11232 //this.list.beginUpdate();
11233 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11234 this.list.alignTo(this.inputEl(), this.listAlign);
11235 this.list.alignTo(this.inputEl(), this.listAlign);
11236 //this.list.endUpdate();
11240 onEmptyResults : function(){
11245 * Returns true if the dropdown list is expanded, else false.
11247 isExpanded : function(){
11248 return this.list.isVisible();
11252 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11253 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11254 * @param {String} value The data value of the item to select
11255 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11256 * selected item if it is not currently in view (defaults to true)
11257 * @return {Boolean} True if the value matched an item in the list, else false
11259 selectByValue : function(v, scrollIntoView){
11260 if(v !== undefined && v !== null){
11261 var r = this.findRecord(this.valueField || this.displayField, v);
11263 this.select(this.store.indexOf(r), scrollIntoView);
11271 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11272 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11273 * @param {Number} index The zero-based index of the list item to select
11274 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11275 * selected item if it is not currently in view (defaults to true)
11277 select : function(index, scrollIntoView){
11278 this.selectedIndex = index;
11279 this.view.select(index);
11280 if(scrollIntoView !== false){
11281 var el = this.view.getNode(index);
11283 //this.innerList.scrollChildIntoView(el, false);
11290 selectNext : function(){
11291 var ct = this.store.getCount();
11293 if(this.selectedIndex == -1){
11295 }else if(this.selectedIndex < ct-1){
11296 this.select(this.selectedIndex+1);
11302 selectPrev : function(){
11303 var ct = this.store.getCount();
11305 if(this.selectedIndex == -1){
11307 }else if(this.selectedIndex != 0){
11308 this.select(this.selectedIndex-1);
11314 onKeyUp : function(e){
11315 if(this.editable !== false && !e.isSpecialKey()){
11316 this.lastKey = e.getKey();
11317 this.dqTask.delay(this.queryDelay);
11322 validateBlur : function(){
11323 return !this.list || !this.list.isVisible();
11327 initQuery : function(){
11328 this.doQuery(this.getRawValue());
11332 doForce : function(){
11333 if(this.inputEl().dom.value.length > 0){
11334 this.inputEl().dom.value =
11335 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11341 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11342 * query allowing the query action to be canceled if needed.
11343 * @param {String} query The SQL query to execute
11344 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11345 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11346 * saved in the current store (defaults to false)
11348 doQuery : function(q, forceAll){
11350 if(q === undefined || q === null){
11355 forceAll: forceAll,
11359 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11364 forceAll = qe.forceAll;
11365 if(forceAll === true || (q.length >= this.minChars)){
11367 this.hasQuery = true;
11369 if(this.lastQuery != q || this.alwaysQuery){
11370 this.lastQuery = q;
11371 if(this.mode == 'local'){
11372 this.selectedIndex = -1;
11374 this.store.clearFilter();
11376 this.store.filter(this.displayField, q);
11380 this.store.baseParams[this.queryParam] = q;
11382 var options = {params : this.getParams(q)};
11385 options.add = true;
11386 options.params.start = this.page * this.pageSize;
11389 this.store.load(options);
11391 * this code will make the page width larger, at the beginning, the list not align correctly,
11392 * we should expand the list on onLoad
11393 * so command out it
11398 this.selectedIndex = -1;
11403 this.loadNext = false;
11407 getParams : function(q){
11409 //p[this.queryParam] = q;
11413 p.limit = this.pageSize;
11419 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11421 collapse : function(){
11422 if(!this.isExpanded()){
11426 this.hasFocus = false;
11432 this.cancelBtn.hide();
11433 this.trigger.show();
11436 Roo.get(document).un('mousedown', this.collapseIf, this);
11437 Roo.get(document).un('mousewheel', this.collapseIf, this);
11438 if (!this.editable) {
11439 Roo.get(document).un('keydown', this.listKeyPress, this);
11441 this.fireEvent('collapse', this);
11445 collapseIf : function(e){
11446 var in_combo = e.within(this.el);
11447 var in_list = e.within(this.list);
11449 if (in_combo || in_list) {
11450 //e.stopPropagation();
11455 this.onTickableFooterButtonClick(e, false, false);
11463 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11465 expand : function(){
11467 if(this.isExpanded() || !this.hasFocus){
11474 this.restrictHeight();
11478 this.tickItems = Roo.apply([], this.item);
11481 this.cancelBtn.show();
11482 this.trigger.hide();
11486 Roo.get(document).on('mousedown', this.collapseIf, this);
11487 Roo.get(document).on('mousewheel', this.collapseIf, this);
11488 if (!this.editable) {
11489 Roo.get(document).on('keydown', this.listKeyPress, this);
11492 this.fireEvent('expand', this);
11496 // Implements the default empty TriggerField.onTriggerClick function
11497 onTriggerClick : function(e)
11499 Roo.log('trigger click');
11501 if(this.disabled || !this.triggerList){
11506 this.loadNext = false;
11508 if(this.isExpanded()){
11510 if (!this.blockFocus) {
11511 this.inputEl().focus();
11515 this.hasFocus = true;
11516 if(this.triggerAction == 'all') {
11517 this.doQuery(this.allQuery, true);
11519 this.doQuery(this.getRawValue());
11521 if (!this.blockFocus) {
11522 this.inputEl().focus();
11527 onTickableTriggerClick : function(e)
11534 this.loadNext = false;
11535 this.hasFocus = true;
11537 if(this.triggerAction == 'all') {
11538 this.doQuery(this.allQuery, true);
11540 this.doQuery(this.getRawValue());
11544 onSearchFieldClick : function(e)
11546 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11551 this.loadNext = false;
11552 this.hasFocus = true;
11554 if(this.triggerAction == 'all') {
11555 this.doQuery(this.allQuery, true);
11557 this.doQuery(this.getRawValue());
11561 listKeyPress : function(e)
11563 //Roo.log('listkeypress');
11564 // scroll to first matching element based on key pres..
11565 if (e.isSpecialKey()) {
11568 var k = String.fromCharCode(e.getKey()).toUpperCase();
11571 var csel = this.view.getSelectedNodes();
11572 var cselitem = false;
11574 var ix = this.view.indexOf(csel[0]);
11575 cselitem = this.store.getAt(ix);
11576 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11582 this.store.each(function(v) {
11584 // start at existing selection.
11585 if (cselitem.id == v.id) {
11591 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11592 match = this.store.indexOf(v);
11598 if (match === false) {
11599 return true; // no more action?
11602 this.view.select(match);
11603 var sn = Roo.get(this.view.getSelectedNodes()[0])
11604 //sn.scrollIntoView(sn.dom.parentNode, false);
11607 onViewScroll : function(e, t){
11609 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11613 this.hasQuery = true;
11615 this.loading = this.list.select('.loading', true).first();
11617 if(this.loading === null){
11618 this.list.createChild({
11620 cls: 'loading select2-more-results select2-active',
11621 html: 'Loading more results...'
11624 this.loading = this.list.select('.loading', true).first();
11626 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11628 this.loading.hide();
11631 this.loading.show();
11636 this.loadNext = true;
11638 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11643 addItem : function(o)
11645 var dv = ''; // display value
11647 if (this.displayField) {
11648 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11650 // this is an error condition!!!
11651 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11658 var choice = this.choices.createChild({
11660 cls: 'select2-search-choice',
11669 cls: 'select2-search-choice-close',
11674 }, this.searchField);
11676 var close = choice.select('a.select2-search-choice-close', true).first()
11678 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11686 this.inputEl().dom.value = '';
11690 onRemoveItem : function(e, _self, o)
11692 e.preventDefault();
11693 var index = this.item.indexOf(o.data) * 1;
11696 Roo.log('not this item?!');
11700 this.item.splice(index, 1);
11705 this.fireEvent('remove', this, e);
11709 syncValue : function()
11711 if(!this.item.length){
11718 Roo.each(this.item, function(i){
11719 if(_this.valueField){
11720 value.push(i[_this.valueField]);
11727 this.value = value.join(',');
11729 if(this.hiddenField){
11730 this.hiddenField.dom.value = this.value;
11734 clearItem : function()
11736 if(!this.multiple){
11742 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11749 inputEl: function ()
11752 return this.searchField;
11754 return this.el.select('input.form-control',true).first();
11758 onTickableFooterButtonClick : function(e, btn, el)
11760 e.preventDefault();
11762 if(btn && btn.name == 'cancel'){
11763 this.tickItems = Roo.apply([], this.item);
11772 Roo.each(this.tickItems, function(o){
11783 * @cfg {Boolean} grow
11787 * @cfg {Number} growMin
11791 * @cfg {Number} growMax
11801 * Ext JS Library 1.1.1
11802 * Copyright(c) 2006-2007, Ext JS, LLC.
11804 * Originally Released Under LGPL - original licence link has changed is not relivant.
11807 * <script type="text/javascript">
11812 * @extends Roo.util.Observable
11813 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11814 * This class also supports single and multi selection modes. <br>
11815 * Create a data model bound view:
11817 var store = new Roo.data.Store(...);
11819 var view = new Roo.View({
11821 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11823 singleSelect: true,
11824 selectedClass: "ydataview-selected",
11828 // listen for node click?
11829 view.on("click", function(vw, index, node, e){
11830 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11834 dataModel.load("foobar.xml");
11836 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11838 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11839 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11841 * Note: old style constructor is still suported (container, template, config)
11844 * Create a new View
11845 * @param {Object} config The config object
11848 Roo.View = function(config, depreciated_tpl, depreciated_config){
11850 this.parent = false;
11852 if (typeof(depreciated_tpl) == 'undefined') {
11853 // new way.. - universal constructor.
11854 Roo.apply(this, config);
11855 this.el = Roo.get(this.el);
11858 this.el = Roo.get(config);
11859 this.tpl = depreciated_tpl;
11860 Roo.apply(this, depreciated_config);
11862 this.wrapEl = this.el.wrap().wrap();
11863 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11866 if(typeof(this.tpl) == "string"){
11867 this.tpl = new Roo.Template(this.tpl);
11869 // support xtype ctors..
11870 this.tpl = new Roo.factory(this.tpl, Roo);
11874 this.tpl.compile();
11879 * @event beforeclick
11880 * Fires before a click is processed. Returns false to cancel the default action.
11881 * @param {Roo.View} this
11882 * @param {Number} index The index of the target node
11883 * @param {HTMLElement} node The target node
11884 * @param {Roo.EventObject} e The raw event object
11886 "beforeclick" : true,
11889 * Fires when a template node is clicked.
11890 * @param {Roo.View} this
11891 * @param {Number} index The index of the target node
11892 * @param {HTMLElement} node The target node
11893 * @param {Roo.EventObject} e The raw event object
11898 * Fires when a template node is double clicked.
11899 * @param {Roo.View} this
11900 * @param {Number} index The index of the target node
11901 * @param {HTMLElement} node The target node
11902 * @param {Roo.EventObject} e The raw event object
11906 * @event contextmenu
11907 * Fires when a template node is right clicked.
11908 * @param {Roo.View} this
11909 * @param {Number} index The index of the target node
11910 * @param {HTMLElement} node The target node
11911 * @param {Roo.EventObject} e The raw event object
11913 "contextmenu" : true,
11915 * @event selectionchange
11916 * Fires when the selected nodes change.
11917 * @param {Roo.View} this
11918 * @param {Array} selections Array of the selected nodes
11920 "selectionchange" : true,
11923 * @event beforeselect
11924 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11925 * @param {Roo.View} this
11926 * @param {HTMLElement} node The node to be selected
11927 * @param {Array} selections Array of currently selected nodes
11929 "beforeselect" : true,
11931 * @event preparedata
11932 * Fires on every row to render, to allow you to change the data.
11933 * @param {Roo.View} this
11934 * @param {Object} data to be rendered (change this)
11936 "preparedata" : true
11944 "click": this.onClick,
11945 "dblclick": this.onDblClick,
11946 "contextmenu": this.onContextMenu,
11950 this.selections = [];
11952 this.cmp = new Roo.CompositeElementLite([]);
11954 this.store = Roo.factory(this.store, Roo.data);
11955 this.setStore(this.store, true);
11958 if ( this.footer && this.footer.xtype) {
11960 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11962 this.footer.dataSource = this.store
11963 this.footer.container = fctr;
11964 this.footer = Roo.factory(this.footer, Roo);
11965 fctr.insertFirst(this.el);
11967 // this is a bit insane - as the paging toolbar seems to detach the el..
11968 // dom.parentNode.parentNode.parentNode
11969 // they get detached?
11973 Roo.View.superclass.constructor.call(this);
11978 Roo.extend(Roo.View, Roo.util.Observable, {
11981 * @cfg {Roo.data.Store} store Data store to load data from.
11986 * @cfg {String|Roo.Element} el The container element.
11991 * @cfg {String|Roo.Template} tpl The template used by this View
11995 * @cfg {String} dataName the named area of the template to use as the data area
11996 * Works with domtemplates roo-name="name"
12000 * @cfg {String} selectedClass The css class to add to selected nodes
12002 selectedClass : "x-view-selected",
12004 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12009 * @cfg {String} text to display on mask (default Loading)
12013 * @cfg {Boolean} multiSelect Allow multiple selection
12015 multiSelect : false,
12017 * @cfg {Boolean} singleSelect Allow single selection
12019 singleSelect: false,
12022 * @cfg {Boolean} toggleSelect - selecting
12024 toggleSelect : false,
12027 * @cfg {Boolean} tickable - selecting
12032 * Returns the element this view is bound to.
12033 * @return {Roo.Element}
12035 getEl : function(){
12036 return this.wrapEl;
12042 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12044 refresh : function(){
12045 Roo.log('refresh');
12048 // if we are using something like 'domtemplate', then
12049 // the what gets used is:
12050 // t.applySubtemplate(NAME, data, wrapping data..)
12051 // the outer template then get' applied with
12052 // the store 'extra data'
12053 // and the body get's added to the
12054 // roo-name="data" node?
12055 // <span class='roo-tpl-{name}'></span> ?????
12059 this.clearSelections();
12060 this.el.update("");
12062 var records = this.store.getRange();
12063 if(records.length < 1) {
12065 // is this valid?? = should it render a template??
12067 this.el.update(this.emptyText);
12071 if (this.dataName) {
12072 this.el.update(t.apply(this.store.meta)); //????
12073 el = this.el.child('.roo-tpl-' + this.dataName);
12076 for(var i = 0, len = records.length; i < len; i++){
12077 var data = this.prepareData(records[i].data, i, records[i]);
12078 this.fireEvent("preparedata", this, data, i, records[i]);
12080 var d = Roo.apply({}, data);
12083 Roo.apply(d, {'roo-id' : Roo.id()});
12087 Roo.each(this.parent.item, function(item){
12088 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12091 Roo.apply(d, {'roo-data-checked' : 'checked'});
12095 html[html.length] = Roo.util.Format.trim(
12097 t.applySubtemplate(this.dataName, d, this.store.meta) :
12104 el.update(html.join(""));
12105 this.nodes = el.dom.childNodes;
12106 this.updateIndexes(0);
12111 * Function to override to reformat the data that is sent to
12112 * the template for each node.
12113 * DEPRICATED - use the preparedata event handler.
12114 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12115 * a JSON object for an UpdateManager bound view).
12117 prepareData : function(data, index, record)
12119 this.fireEvent("preparedata", this, data, index, record);
12123 onUpdate : function(ds, record){
12124 Roo.log('on update');
12125 this.clearSelections();
12126 var index = this.store.indexOf(record);
12127 var n = this.nodes[index];
12128 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12129 n.parentNode.removeChild(n);
12130 this.updateIndexes(index, index);
12136 onAdd : function(ds, records, index)
12138 Roo.log(['on Add', ds, records, index] );
12139 this.clearSelections();
12140 if(this.nodes.length == 0){
12144 var n = this.nodes[index];
12145 for(var i = 0, len = records.length; i < len; i++){
12146 var d = this.prepareData(records[i].data, i, records[i]);
12148 this.tpl.insertBefore(n, d);
12151 this.tpl.append(this.el, d);
12154 this.updateIndexes(index);
12157 onRemove : function(ds, record, index){
12158 Roo.log('onRemove');
12159 this.clearSelections();
12160 var el = this.dataName ?
12161 this.el.child('.roo-tpl-' + this.dataName) :
12164 el.dom.removeChild(this.nodes[index]);
12165 this.updateIndexes(index);
12169 * Refresh an individual node.
12170 * @param {Number} index
12172 refreshNode : function(index){
12173 this.onUpdate(this.store, this.store.getAt(index));
12176 updateIndexes : function(startIndex, endIndex){
12177 var ns = this.nodes;
12178 startIndex = startIndex || 0;
12179 endIndex = endIndex || ns.length - 1;
12180 for(var i = startIndex; i <= endIndex; i++){
12181 ns[i].nodeIndex = i;
12186 * Changes the data store this view uses and refresh the view.
12187 * @param {Store} store
12189 setStore : function(store, initial){
12190 if(!initial && this.store){
12191 this.store.un("datachanged", this.refresh);
12192 this.store.un("add", this.onAdd);
12193 this.store.un("remove", this.onRemove);
12194 this.store.un("update", this.onUpdate);
12195 this.store.un("clear", this.refresh);
12196 this.store.un("beforeload", this.onBeforeLoad);
12197 this.store.un("load", this.onLoad);
12198 this.store.un("loadexception", this.onLoad);
12202 store.on("datachanged", this.refresh, this);
12203 store.on("add", this.onAdd, this);
12204 store.on("remove", this.onRemove, this);
12205 store.on("update", this.onUpdate, this);
12206 store.on("clear", this.refresh, this);
12207 store.on("beforeload", this.onBeforeLoad, this);
12208 store.on("load", this.onLoad, this);
12209 store.on("loadexception", this.onLoad, this);
12217 * onbeforeLoad - masks the loading area.
12220 onBeforeLoad : function(store,opts)
12222 Roo.log('onBeforeLoad');
12224 this.el.update("");
12226 this.el.mask(this.mask ? this.mask : "Loading" );
12228 onLoad : function ()
12235 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12236 * @param {HTMLElement} node
12237 * @return {HTMLElement} The template node
12239 findItemFromChild : function(node){
12240 var el = this.dataName ?
12241 this.el.child('.roo-tpl-' + this.dataName,true) :
12244 if(!node || node.parentNode == el){
12247 var p = node.parentNode;
12248 while(p && p != el){
12249 if(p.parentNode == el){
12258 onClick : function(e){
12259 var item = this.findItemFromChild(e.getTarget());
12261 var index = this.indexOf(item);
12262 if(this.onItemClick(item, index, e) !== false){
12263 this.fireEvent("click", this, index, item, e);
12266 this.clearSelections();
12271 onContextMenu : function(e){
12272 var item = this.findItemFromChild(e.getTarget());
12274 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12279 onDblClick : function(e){
12280 var item = this.findItemFromChild(e.getTarget());
12282 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12286 onItemClick : function(item, index, e)
12288 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12291 if (this.toggleSelect) {
12292 var m = this.isSelected(item) ? 'unselect' : 'select';
12295 _t[m](item, true, false);
12298 if(this.multiSelect || this.singleSelect){
12299 if(this.multiSelect && e.shiftKey && this.lastSelection){
12300 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12302 this.select(item, this.multiSelect && e.ctrlKey);
12303 this.lastSelection = item;
12306 if(!this.tickable){
12307 e.preventDefault();
12315 * Get the number of selected nodes.
12318 getSelectionCount : function(){
12319 return this.selections.length;
12323 * Get the currently selected nodes.
12324 * @return {Array} An array of HTMLElements
12326 getSelectedNodes : function(){
12327 return this.selections;
12331 * Get the indexes of the selected nodes.
12334 getSelectedIndexes : function(){
12335 var indexes = [], s = this.selections;
12336 for(var i = 0, len = s.length; i < len; i++){
12337 indexes.push(s[i].nodeIndex);
12343 * Clear all selections
12344 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12346 clearSelections : function(suppressEvent){
12347 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12348 this.cmp.elements = this.selections;
12349 this.cmp.removeClass(this.selectedClass);
12350 this.selections = [];
12351 if(!suppressEvent){
12352 this.fireEvent("selectionchange", this, this.selections);
12358 * Returns true if the passed node is selected
12359 * @param {HTMLElement/Number} node The node or node index
12360 * @return {Boolean}
12362 isSelected : function(node){
12363 var s = this.selections;
12367 node = this.getNode(node);
12368 return s.indexOf(node) !== -1;
12373 * @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
12374 * @param {Boolean} keepExisting (optional) true to keep existing selections
12375 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12377 select : function(nodeInfo, keepExisting, suppressEvent){
12378 if(nodeInfo instanceof Array){
12380 this.clearSelections(true);
12382 for(var i = 0, len = nodeInfo.length; i < len; i++){
12383 this.select(nodeInfo[i], true, true);
12387 var node = this.getNode(nodeInfo);
12388 if(!node || this.isSelected(node)){
12389 return; // already selected.
12392 this.clearSelections(true);
12394 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12395 Roo.fly(node).addClass(this.selectedClass);
12396 this.selections.push(node);
12397 if(!suppressEvent){
12398 this.fireEvent("selectionchange", this, this.selections);
12406 * @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
12407 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12408 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12410 unselect : function(nodeInfo, keepExisting, suppressEvent)
12412 if(nodeInfo instanceof Array){
12413 Roo.each(this.selections, function(s) {
12414 this.unselect(s, nodeInfo);
12418 var node = this.getNode(nodeInfo);
12419 if(!node || !this.isSelected(node)){
12420 Roo.log("not selected");
12421 return; // not selected.
12425 Roo.each(this.selections, function(s) {
12427 Roo.fly(node).removeClass(this.selectedClass);
12434 this.selections= ns;
12435 this.fireEvent("selectionchange", this, this.selections);
12439 * Gets a template node.
12440 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12441 * @return {HTMLElement} The node or null if it wasn't found
12443 getNode : function(nodeInfo){
12444 if(typeof nodeInfo == "string"){
12445 return document.getElementById(nodeInfo);
12446 }else if(typeof nodeInfo == "number"){
12447 return this.nodes[nodeInfo];
12453 * Gets a range template nodes.
12454 * @param {Number} startIndex
12455 * @param {Number} endIndex
12456 * @return {Array} An array of nodes
12458 getNodes : function(start, end){
12459 var ns = this.nodes;
12460 start = start || 0;
12461 end = typeof end == "undefined" ? ns.length - 1 : end;
12464 for(var i = start; i <= end; i++){
12468 for(var i = start; i >= end; i--){
12476 * Finds the index of the passed node
12477 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12478 * @return {Number} The index of the node or -1
12480 indexOf : function(node){
12481 node = this.getNode(node);
12482 if(typeof node.nodeIndex == "number"){
12483 return node.nodeIndex;
12485 var ns = this.nodes;
12486 for(var i = 0, len = ns.length; i < len; i++){
12497 * based on jquery fullcalendar
12501 Roo.bootstrap = Roo.bootstrap || {};
12503 * @class Roo.bootstrap.Calendar
12504 * @extends Roo.bootstrap.Component
12505 * Bootstrap Calendar class
12506 * @cfg {Boolean} loadMask (true|false) default false
12507 * @cfg {Object} header generate the user specific header of the calendar, default false
12510 * Create a new Container
12511 * @param {Object} config The config object
12516 Roo.bootstrap.Calendar = function(config){
12517 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12521 * Fires when a date is selected
12522 * @param {DatePicker} this
12523 * @param {Date} date The selected date
12527 * @event monthchange
12528 * Fires when the displayed month changes
12529 * @param {DatePicker} this
12530 * @param {Date} date The selected month
12532 'monthchange': true,
12534 * @event evententer
12535 * Fires when mouse over an event
12536 * @param {Calendar} this
12537 * @param {event} Event
12539 'evententer': true,
12541 * @event eventleave
12542 * Fires when the mouse leaves an
12543 * @param {Calendar} this
12546 'eventleave': true,
12548 * @event eventclick
12549 * Fires when the mouse click an
12550 * @param {Calendar} this
12559 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12562 * @cfg {Number} startDay
12563 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12571 getAutoCreate : function(){
12574 var fc_button = function(name, corner, style, content ) {
12575 return Roo.apply({},{
12577 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12579 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12582 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12593 style : 'width:100%',
12600 cls : 'fc-header-left',
12602 fc_button('prev', 'left', 'arrow', '‹' ),
12603 fc_button('next', 'right', 'arrow', '›' ),
12604 { tag: 'span', cls: 'fc-header-space' },
12605 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12613 cls : 'fc-header-center',
12617 cls: 'fc-header-title',
12620 html : 'month / year'
12628 cls : 'fc-header-right',
12630 /* fc_button('month', 'left', '', 'month' ),
12631 fc_button('week', '', '', 'week' ),
12632 fc_button('day', 'right', '', 'day' )
12644 header = this.header;
12647 var cal_heads = function() {
12649 // fixme - handle this.
12651 for (var i =0; i < Date.dayNames.length; i++) {
12652 var d = Date.dayNames[i];
12655 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12656 html : d.substring(0,3)
12660 ret[0].cls += ' fc-first';
12661 ret[6].cls += ' fc-last';
12664 var cal_cell = function(n) {
12667 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12672 cls: 'fc-day-number',
12676 cls: 'fc-day-content',
12680 style: 'position: relative;' // height: 17px;
12692 var cal_rows = function() {
12695 for (var r = 0; r < 6; r++) {
12702 for (var i =0; i < Date.dayNames.length; i++) {
12703 var d = Date.dayNames[i];
12704 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12707 row.cn[0].cls+=' fc-first';
12708 row.cn[0].cn[0].style = 'min-height:90px';
12709 row.cn[6].cls+=' fc-last';
12713 ret[0].cls += ' fc-first';
12714 ret[4].cls += ' fc-prev-last';
12715 ret[5].cls += ' fc-last';
12722 cls: 'fc-border-separate',
12723 style : 'width:100%',
12731 cls : 'fc-first fc-last',
12749 cls : 'fc-content',
12750 style : "position: relative;",
12753 cls : 'fc-view fc-view-month fc-grid',
12754 style : 'position: relative',
12755 unselectable : 'on',
12758 cls : 'fc-event-container',
12759 style : 'position:absolute;z-index:8;top:0;left:0;'
12777 initEvents : function()
12780 throw "can not find store for calendar";
12786 style: "text-align:center",
12790 style: "background-color:white;width:50%;margin:250 auto",
12794 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12805 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12807 var size = this.el.select('.fc-content', true).first().getSize();
12808 this.maskEl.setSize(size.width, size.height);
12809 this.maskEl.enableDisplayMode("block");
12810 if(!this.loadMask){
12811 this.maskEl.hide();
12814 this.store = Roo.factory(this.store, Roo.data);
12815 this.store.on('load', this.onLoad, this);
12816 this.store.on('beforeload', this.onBeforeLoad, this);
12820 this.cells = this.el.select('.fc-day',true);
12821 //Roo.log(this.cells);
12822 this.textNodes = this.el.query('.fc-day-number');
12823 this.cells.addClassOnOver('fc-state-hover');
12825 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12826 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12827 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12828 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12830 this.on('monthchange', this.onMonthChange, this);
12832 this.update(new Date().clearTime());
12835 resize : function() {
12836 var sz = this.el.getSize();
12838 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12839 this.el.select('.fc-day-content div',true).setHeight(34);
12844 showPrevMonth : function(e){
12845 this.update(this.activeDate.add("mo", -1));
12847 showToday : function(e){
12848 this.update(new Date().clearTime());
12851 showNextMonth : function(e){
12852 this.update(this.activeDate.add("mo", 1));
12856 showPrevYear : function(){
12857 this.update(this.activeDate.add("y", -1));
12861 showNextYear : function(){
12862 this.update(this.activeDate.add("y", 1));
12867 update : function(date)
12869 var vd = this.activeDate;
12870 this.activeDate = date;
12871 // if(vd && this.el){
12872 // var t = date.getTime();
12873 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12874 // Roo.log('using add remove');
12876 // this.fireEvent('monthchange', this, date);
12878 // this.cells.removeClass("fc-state-highlight");
12879 // this.cells.each(function(c){
12880 // if(c.dateValue == t){
12881 // c.addClass("fc-state-highlight");
12882 // setTimeout(function(){
12883 // try{c.dom.firstChild.focus();}catch(e){}
12893 var days = date.getDaysInMonth();
12895 var firstOfMonth = date.getFirstDateOfMonth();
12896 var startingPos = firstOfMonth.getDay()-this.startDay;
12898 if(startingPos < this.startDay){
12902 var pm = date.add(Date.MONTH, -1);
12903 var prevStart = pm.getDaysInMonth()-startingPos;
12905 this.cells = this.el.select('.fc-day',true);
12906 this.textNodes = this.el.query('.fc-day-number');
12907 this.cells.addClassOnOver('fc-state-hover');
12909 var cells = this.cells.elements;
12910 var textEls = this.textNodes;
12912 Roo.each(cells, function(cell){
12913 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12916 days += startingPos;
12918 // convert everything to numbers so it's fast
12919 var day = 86400000;
12920 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12923 //Roo.log(prevStart);
12925 var today = new Date().clearTime().getTime();
12926 var sel = date.clearTime().getTime();
12927 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12928 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12929 var ddMatch = this.disabledDatesRE;
12930 var ddText = this.disabledDatesText;
12931 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12932 var ddaysText = this.disabledDaysText;
12933 var format = this.format;
12935 var setCellClass = function(cal, cell){
12939 //Roo.log('set Cell Class');
12941 var t = d.getTime();
12945 cell.dateValue = t;
12947 cell.className += " fc-today";
12948 cell.className += " fc-state-highlight";
12949 cell.title = cal.todayText;
12952 // disable highlight in other month..
12953 //cell.className += " fc-state-highlight";
12958 cell.className = " fc-state-disabled";
12959 cell.title = cal.minText;
12963 cell.className = " fc-state-disabled";
12964 cell.title = cal.maxText;
12968 if(ddays.indexOf(d.getDay()) != -1){
12969 cell.title = ddaysText;
12970 cell.className = " fc-state-disabled";
12973 if(ddMatch && format){
12974 var fvalue = d.dateFormat(format);
12975 if(ddMatch.test(fvalue)){
12976 cell.title = ddText.replace("%0", fvalue);
12977 cell.className = " fc-state-disabled";
12981 if (!cell.initialClassName) {
12982 cell.initialClassName = cell.dom.className;
12985 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12990 for(; i < startingPos; i++) {
12991 textEls[i].innerHTML = (++prevStart);
12992 d.setDate(d.getDate()+1);
12994 cells[i].className = "fc-past fc-other-month";
12995 setCellClass(this, cells[i]);
13000 for(; i < days; i++){
13001 intDay = i - startingPos + 1;
13002 textEls[i].innerHTML = (intDay);
13003 d.setDate(d.getDate()+1);
13005 cells[i].className = ''; // "x-date-active";
13006 setCellClass(this, cells[i]);
13010 for(; i < 42; i++) {
13011 textEls[i].innerHTML = (++extraDays);
13012 d.setDate(d.getDate()+1);
13014 cells[i].className = "fc-future fc-other-month";
13015 setCellClass(this, cells[i]);
13018 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13020 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13022 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13023 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13025 if(totalRows != 6){
13026 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13027 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13030 this.fireEvent('monthchange', this, date);
13034 if(!this.internalRender){
13035 var main = this.el.dom.firstChild;
13036 var w = main.offsetWidth;
13037 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13038 Roo.fly(main).setWidth(w);
13039 this.internalRender = true;
13040 // opera does not respect the auto grow header center column
13041 // then, after it gets a width opera refuses to recalculate
13042 // without a second pass
13043 if(Roo.isOpera && !this.secondPass){
13044 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13045 this.secondPass = true;
13046 this.update.defer(10, this, [date]);
13053 findCell : function(dt) {
13054 dt = dt.clearTime().getTime();
13056 this.cells.each(function(c){
13057 //Roo.log("check " +c.dateValue + '?=' + dt);
13058 if(c.dateValue == dt){
13068 findCells : function(ev) {
13069 var s = ev.start.clone().clearTime().getTime();
13071 var e= ev.end.clone().clearTime().getTime();
13074 this.cells.each(function(c){
13075 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13077 if(c.dateValue > e){
13080 if(c.dateValue < s){
13089 // findBestRow: function(cells)
13093 // for (var i =0 ; i < cells.length;i++) {
13094 // ret = Math.max(cells[i].rows || 0,ret);
13101 addItem : function(ev)
13103 // look for vertical location slot in
13104 var cells = this.findCells(ev);
13106 // ev.row = this.findBestRow(cells);
13108 // work out the location.
13112 for(var i =0; i < cells.length; i++) {
13114 cells[i].row = cells[0].row;
13117 cells[i].row = cells[i].row + 1;
13127 if (crow.start.getY() == cells[i].getY()) {
13129 crow.end = cells[i];
13146 cells[0].events.push(ev);
13148 this.calevents.push(ev);
13151 clearEvents: function() {
13153 if(!this.calevents){
13157 Roo.each(this.cells.elements, function(c){
13163 Roo.each(this.calevents, function(e) {
13164 Roo.each(e.els, function(el) {
13165 el.un('mouseenter' ,this.onEventEnter, this);
13166 el.un('mouseleave' ,this.onEventLeave, this);
13171 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13177 renderEvents: function()
13181 this.cells.each(function(c) {
13190 if(c.row != c.events.length){
13191 r = 4 - (4 - (c.row - c.events.length));
13194 c.events = ev.slice(0, r);
13195 c.more = ev.slice(r);
13197 if(c.more.length && c.more.length == 1){
13198 c.events.push(c.more.pop());
13201 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13205 this.cells.each(function(c) {
13207 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13210 for (var e = 0; e < c.events.length; e++){
13211 var ev = c.events[e];
13212 var rows = ev.rows;
13214 for(var i = 0; i < rows.length; i++) {
13216 // how many rows should it span..
13219 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13220 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13222 unselectable : "on",
13225 cls: 'fc-event-inner',
13229 // cls: 'fc-event-time',
13230 // html : cells.length > 1 ? '' : ev.time
13234 cls: 'fc-event-title',
13235 html : String.format('{0}', ev.title)
13242 cls: 'ui-resizable-handle ui-resizable-e',
13243 html : '  '
13250 cfg.cls += ' fc-event-start';
13252 if ((i+1) == rows.length) {
13253 cfg.cls += ' fc-event-end';
13256 var ctr = _this.el.select('.fc-event-container',true).first();
13257 var cg = ctr.createChild(cfg);
13259 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13260 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13262 var r = (c.more.length) ? 1 : 0;
13263 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13264 cg.setWidth(ebox.right - sbox.x -2);
13266 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13267 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13268 cg.on('click', _this.onEventClick, _this, ev);
13279 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13280 style : 'position: absolute',
13281 unselectable : "on",
13284 cls: 'fc-event-inner',
13288 cls: 'fc-event-title',
13296 cls: 'ui-resizable-handle ui-resizable-e',
13297 html : '  '
13303 var ctr = _this.el.select('.fc-event-container',true).first();
13304 var cg = ctr.createChild(cfg);
13306 var sbox = c.select('.fc-day-content',true).first().getBox();
13307 var ebox = c.select('.fc-day-content',true).first().getBox();
13309 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13310 cg.setWidth(ebox.right - sbox.x -2);
13312 cg.on('click', _this.onMoreEventClick, _this, c.more);
13322 onEventEnter: function (e, el,event,d) {
13323 this.fireEvent('evententer', this, el, event);
13326 onEventLeave: function (e, el,event,d) {
13327 this.fireEvent('eventleave', this, el, event);
13330 onEventClick: function (e, el,event,d) {
13331 this.fireEvent('eventclick', this, el, event);
13334 onMonthChange: function () {
13338 onMoreEventClick: function(e, el, more)
13342 this.calpopover.placement = 'right';
13343 this.calpopover.setTitle('More');
13345 this.calpopover.setContent('');
13347 var ctr = this.calpopover.el.select('.popover-content', true).first();
13349 Roo.each(more, function(m){
13351 cls : 'fc-event-hori fc-event-draggable',
13354 var cg = ctr.createChild(cfg);
13356 cg.on('click', _this.onEventClick, _this, m);
13359 this.calpopover.show(el);
13364 onLoad: function ()
13366 this.calevents = [];
13369 if(this.store.getCount() > 0){
13370 this.store.data.each(function(d){
13373 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13374 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13375 time : d.data.start_time,
13376 title : d.data.title,
13377 description : d.data.description,
13378 venue : d.data.venue
13383 this.renderEvents();
13385 if(this.calevents.length && this.loadMask){
13386 this.maskEl.hide();
13390 onBeforeLoad: function()
13392 this.clearEvents();
13394 this.maskEl.show();
13408 * @class Roo.bootstrap.Popover
13409 * @extends Roo.bootstrap.Component
13410 * Bootstrap Popover class
13411 * @cfg {String} html contents of the popover (or false to use children..)
13412 * @cfg {String} title of popover (or false to hide)
13413 * @cfg {String} placement how it is placed
13414 * @cfg {String} trigger click || hover (or false to trigger manually)
13415 * @cfg {String} over what (parent or false to trigger manually.)
13418 * Create a new Popover
13419 * @param {Object} config The config object
13422 Roo.bootstrap.Popover = function(config){
13423 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13426 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13428 title: 'Fill in a title',
13431 placement : 'right',
13432 trigger : 'hover', // hover
13436 can_build_overlaid : false,
13438 getChildContainer : function()
13440 return this.el.select('.popover-content',true).first();
13443 getAutoCreate : function(){
13444 Roo.log('make popover?');
13446 cls : 'popover roo-dynamic',
13447 style: 'display:block',
13453 cls : 'popover-inner',
13457 cls: 'popover-title',
13461 cls : 'popover-content',
13472 setTitle: function(str)
13474 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13476 setContent: function(str)
13478 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13480 // as it get's added to the bottom of the page.
13481 onRender : function(ct, position)
13483 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13485 var cfg = Roo.apply({}, this.getAutoCreate());
13489 cfg.cls += ' ' + this.cls;
13492 cfg.style = this.style;
13494 Roo.log("adding to ")
13495 this.el = Roo.get(document.body).createChild(cfg, position);
13501 initEvents : function()
13503 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13504 this.el.enableDisplayMode('block');
13506 if (this.over === false) {
13509 if (this.triggers === false) {
13512 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13513 var triggers = this.trigger ? this.trigger.split(' ') : [];
13514 Roo.each(triggers, function(trigger) {
13516 if (trigger == 'click') {
13517 on_el.on('click', this.toggle, this);
13518 } else if (trigger != 'manual') {
13519 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13520 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13522 on_el.on(eventIn ,this.enter, this);
13523 on_el.on(eventOut, this.leave, this);
13534 toggle : function () {
13535 this.hoverState == 'in' ? this.leave() : this.enter();
13538 enter : function () {
13541 clearTimeout(this.timeout);
13543 this.hoverState = 'in'
13545 if (!this.delay || !this.delay.show) {
13550 this.timeout = setTimeout(function () {
13551 if (_t.hoverState == 'in') {
13554 }, this.delay.show)
13556 leave : function() {
13557 clearTimeout(this.timeout);
13559 this.hoverState = 'out'
13561 if (!this.delay || !this.delay.hide) {
13566 this.timeout = setTimeout(function () {
13567 if (_t.hoverState == 'out') {
13570 }, this.delay.hide)
13573 show : function (on_el)
13576 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13579 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13580 if (this.html !== false) {
13581 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13583 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13584 if (!this.title.length) {
13585 this.el.select('.popover-title',true).hide();
13588 var placement = typeof this.placement == 'function' ?
13589 this.placement.call(this, this.el, on_el) :
13592 var autoToken = /\s?auto?\s?/i;
13593 var autoPlace = autoToken.test(placement);
13595 placement = placement.replace(autoToken, '') || 'top';
13599 //this.el.setXY([0,0]);
13601 this.el.dom.style.display='block';
13602 this.el.addClass(placement);
13604 //this.el.appendTo(on_el);
13606 var p = this.getPosition();
13607 var box = this.el.getBox();
13612 var align = Roo.bootstrap.Popover.alignment[placement]
13613 this.el.alignTo(on_el, align[0],align[1]);
13614 //var arrow = this.el.select('.arrow',true).first();
13615 //arrow.set(align[2],
13617 this.el.addClass('in');
13618 this.hoverState = null;
13620 if (this.el.hasClass('fade')) {
13627 this.el.setXY([0,0]);
13628 this.el.removeClass('in');
13635 Roo.bootstrap.Popover.alignment = {
13636 'left' : ['r-l', [-10,0], 'right'],
13637 'right' : ['l-r', [10,0], 'left'],
13638 'bottom' : ['t-b', [0,10], 'top'],
13639 'top' : [ 'b-t', [0,-10], 'bottom']
13650 * @class Roo.bootstrap.Progress
13651 * @extends Roo.bootstrap.Component
13652 * Bootstrap Progress class
13653 * @cfg {Boolean} striped striped of the progress bar
13654 * @cfg {Boolean} active animated of the progress bar
13658 * Create a new Progress
13659 * @param {Object} config The config object
13662 Roo.bootstrap.Progress = function(config){
13663 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13666 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13671 getAutoCreate : function(){
13679 cfg.cls += ' progress-striped';
13683 cfg.cls += ' active';
13702 * @class Roo.bootstrap.ProgressBar
13703 * @extends Roo.bootstrap.Component
13704 * Bootstrap ProgressBar class
13705 * @cfg {Number} aria_valuenow aria-value now
13706 * @cfg {Number} aria_valuemin aria-value min
13707 * @cfg {Number} aria_valuemax aria-value max
13708 * @cfg {String} label label for the progress bar
13709 * @cfg {String} panel (success | info | warning | danger )
13710 * @cfg {String} role role of the progress bar
13711 * @cfg {String} sr_only text
13715 * Create a new ProgressBar
13716 * @param {Object} config The config object
13719 Roo.bootstrap.ProgressBar = function(config){
13720 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13723 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13727 aria_valuemax : 100,
13733 getAutoCreate : function()
13738 cls: 'progress-bar',
13739 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13751 cfg.role = this.role;
13754 if(this.aria_valuenow){
13755 cfg['aria-valuenow'] = this.aria_valuenow;
13758 if(this.aria_valuemin){
13759 cfg['aria-valuemin'] = this.aria_valuemin;
13762 if(this.aria_valuemax){
13763 cfg['aria-valuemax'] = this.aria_valuemax;
13766 if(this.label && !this.sr_only){
13767 cfg.html = this.label;
13771 cfg.cls += ' progress-bar-' + this.panel;
13777 update : function(aria_valuenow)
13779 this.aria_valuenow = aria_valuenow;
13781 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13796 * @class Roo.bootstrap.TabGroup
13797 * @extends Roo.bootstrap.Column
13798 * Bootstrap Column class
13799 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13800 * @cfg {Boolean} carousel true to make the group behave like a carousel
13803 * Create a new TabGroup
13804 * @param {Object} config The config object
13807 Roo.bootstrap.TabGroup = function(config){
13808 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13810 this.navId = Roo.id();
13813 Roo.bootstrap.TabGroup.register(this);
13817 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13821 getAutoCreate : function()
13823 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13825 cfg.cls += ' tab-content';
13827 if (this.carousel) {
13828 cfg.cls += ' carousel slide';
13830 cls : 'carousel-inner'
13837 getChildContainer : function()
13839 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13843 * register a Navigation item
13844 * @param {Roo.bootstrap.NavItem} the navitem to add
13846 register : function(item)
13848 this.tabs.push( item);
13849 item.navId = this.navId; // not really needed..
13853 getActivePanel : function()
13856 Roo.each(this.tabs, function(t) {
13866 getPanelByName : function(n)
13869 Roo.each(this.tabs, function(t) {
13870 if (t.tabId == n) {
13878 indexOfPanel : function(p)
13881 Roo.each(this.tabs, function(t,i) {
13882 if (t.tabId == p.tabId) {
13891 * show a specific panel
13892 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13893 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13895 showPanel : function (pan)
13900 if (typeof(pan) == 'number') {
13901 pan = this.tabs[pan];
13903 if (typeof(pan) == 'string') {
13904 pan = this.getPanelByName(pan);
13906 if (pan.tabId == this.getActivePanel().tabId) {
13909 var cur = this.getActivePanel();
13911 if (false === cur.fireEvent('beforedeactivate')) {
13917 if (this.carousel) {
13918 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13919 var lr = dir == 'next' ? 'left' : 'right';
13920 pan.el.addClass(dir); // or prev
13921 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13922 cur.el.addClass(lr); // or right
13923 pan.el.addClass(lr);
13924 cur.el.on('transitionend', function() {
13925 Roo.log("trans end?");
13927 pan.el.removeClass([lr,dir]);
13928 pan.setActive(true);
13930 cur.el.removeClass([lr]);
13931 cur.setActive(false);
13934 }, this, { single: true } );
13938 cur.setActive(false);
13939 pan.setActive(true);
13943 showPanelNext : function()
13945 var i = this.indexOfPanel(this.getActivePanel());
13946 if (i > this.tabs.length) {
13949 this.showPanel(this.tabs[i+1]);
13951 showPanelPrev : function()
13953 var i = this.indexOfPanel(this.getActivePanel());
13957 this.showPanel(this.tabs[i-1]);
13968 Roo.apply(Roo.bootstrap.TabGroup, {
13972 * register a Navigation Group
13973 * @param {Roo.bootstrap.NavGroup} the navgroup to add
13975 register : function(navgrp)
13977 this.groups[navgrp.navId] = navgrp;
13981 * fetch a Navigation Group based on the navigation ID
13982 * if one does not exist , it will get created.
13983 * @param {string} the navgroup to add
13984 * @returns {Roo.bootstrap.NavGroup} the navgroup
13986 get: function(navId) {
13987 if (typeof(this.groups[navId]) == 'undefined') {
13988 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
13990 return this.groups[navId] ;
14005 * @class Roo.bootstrap.TabPanel
14006 * @extends Roo.bootstrap.Component
14007 * Bootstrap TabPanel class
14008 * @cfg {Boolean} active panel active
14009 * @cfg {String} html panel content
14010 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14011 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14015 * Create a new TabPanel
14016 * @param {Object} config The config object
14019 Roo.bootstrap.TabPanel = function(config){
14020 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14024 * Fires when the active status changes
14025 * @param {Roo.bootstrap.TabPanel} this
14026 * @param {Boolean} state the new state
14031 * @event beforedeactivate
14032 * Fires before a tab is de-activated - can be used to do validation on a form.
14033 * @param {Roo.bootstrap.TabPanel} this
14034 * @return {Boolean} false if there is an error
14037 'beforedeactivate': true
14040 this.tabId = this.tabId || Roo.id();
14044 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14051 getAutoCreate : function(){
14054 // item is needed for carousel - not sure if it has any effect otherwise
14055 cls: 'tab-pane item',
14056 html: this.html || ''
14060 cfg.cls += ' active';
14064 cfg.tabId = this.tabId;
14071 initEvents: function()
14073 Roo.log('-------- init events on tab panel ---------');
14075 var p = this.parent();
14076 this.navId = this.navId || p.navId;
14078 if (typeof(this.navId) != 'undefined') {
14079 // not really needed.. but just in case.. parent should be a NavGroup.
14080 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14081 Roo.log(['register', tg, this]);
14087 onRender : function(ct, position)
14089 // Roo.log("Call onRender: " + this.xtype);
14091 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14099 setActive: function(state)
14101 Roo.log("panel - set active " + this.tabId + "=" + state);
14103 this.active = state;
14105 this.el.removeClass('active');
14107 } else if (!this.el.hasClass('active')) {
14108 this.el.addClass('active');
14110 this.fireEvent('changed', this, state);
14127 * @class Roo.bootstrap.DateField
14128 * @extends Roo.bootstrap.Input
14129 * Bootstrap DateField class
14130 * @cfg {Number} weekStart default 0
14131 * @cfg {Number} weekStart default 0
14132 * @cfg {Number} viewMode default empty, (months|years)
14133 * @cfg {Number} minViewMode default empty, (months|years)
14134 * @cfg {Number} startDate default -Infinity
14135 * @cfg {Number} endDate default Infinity
14136 * @cfg {Boolean} todayHighlight default false
14137 * @cfg {Boolean} todayBtn default false
14138 * @cfg {Boolean} calendarWeeks default false
14139 * @cfg {Object} daysOfWeekDisabled default empty
14141 * @cfg {Boolean} keyboardNavigation default true
14142 * @cfg {String} language default en
14145 * Create a new DateField
14146 * @param {Object} config The config object
14149 Roo.bootstrap.DateField = function(config){
14150 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14154 * Fires when this field show.
14155 * @param {Roo.bootstrap.DateField} this
14156 * @param {Mixed} date The date value
14161 * Fires when this field hide.
14162 * @param {Roo.bootstrap.DateField} this
14163 * @param {Mixed} date The date value
14168 * Fires when select a date.
14169 * @param {Roo.bootstrap.DateField} this
14170 * @param {Mixed} date The date value
14176 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14179 * @cfg {String} format
14180 * The default date format string which can be overriden for localization support. The format must be
14181 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14185 * @cfg {String} altFormats
14186 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14187 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14189 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14197 todayHighlight : false,
14203 keyboardNavigation: true,
14205 calendarWeeks: false,
14207 startDate: -Infinity,
14211 daysOfWeekDisabled: [],
14215 UTCDate: function()
14217 return new Date(Date.UTC.apply(Date, arguments));
14220 UTCToday: function()
14222 var today = new Date();
14223 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14226 getDate: function() {
14227 var d = this.getUTCDate();
14228 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14231 getUTCDate: function() {
14235 setDate: function(d) {
14236 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14239 setUTCDate: function(d) {
14241 this.setValue(this.formatDate(this.date));
14244 onRender: function(ct, position)
14247 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14249 this.language = this.language || 'en';
14250 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14251 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14253 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14254 this.format = this.format || 'm/d/y';
14255 this.isInline = false;
14256 this.isInput = true;
14257 this.component = this.el.select('.add-on', true).first() || false;
14258 this.component = (this.component && this.component.length === 0) ? false : this.component;
14259 this.hasInput = this.component && this.inputEL().length;
14261 if (typeof(this.minViewMode === 'string')) {
14262 switch (this.minViewMode) {
14264 this.minViewMode = 1;
14267 this.minViewMode = 2;
14270 this.minViewMode = 0;
14275 if (typeof(this.viewMode === 'string')) {
14276 switch (this.viewMode) {
14289 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14291 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14293 this.picker().on('mousedown', this.onMousedown, this);
14294 this.picker().on('click', this.onClick, this);
14296 this.picker().addClass('datepicker-dropdown');
14298 this.startViewMode = this.viewMode;
14301 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14302 if(!this.calendarWeeks){
14307 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14308 v.attr('colspan', function(i, val){
14309 return parseInt(val) + 1;
14314 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14316 this.setStartDate(this.startDate);
14317 this.setEndDate(this.endDate);
14319 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14326 if(this.isInline) {
14331 picker : function()
14333 return this.el.select('.datepicker', true).first();
14336 fillDow: function()
14338 var dowCnt = this.weekStart;
14347 if(this.calendarWeeks){
14355 while (dowCnt < this.weekStart + 7) {
14359 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14363 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14366 fillMonths: function()
14369 var months = this.picker().select('>.datepicker-months td', true).first();
14371 months.dom.innerHTML = '';
14377 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14380 months.createChild(month);
14388 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14390 if (this.date < this.startDate) {
14391 this.viewDate = new Date(this.startDate);
14392 } else if (this.date > this.endDate) {
14393 this.viewDate = new Date(this.endDate);
14395 this.viewDate = new Date(this.date);
14403 var d = new Date(this.viewDate),
14404 year = d.getUTCFullYear(),
14405 month = d.getUTCMonth(),
14406 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14407 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14408 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14409 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14410 currentDate = this.date && this.date.valueOf(),
14411 today = this.UTCToday();
14413 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14415 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14417 // this.picker.select('>tfoot th.today').
14418 // .text(dates[this.language].today)
14419 // .toggle(this.todayBtn !== false);
14421 this.updateNavArrows();
14424 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14426 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14428 prevMonth.setUTCDate(day);
14430 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14432 var nextMonth = new Date(prevMonth);
14434 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14436 nextMonth = nextMonth.valueOf();
14438 var fillMonths = false;
14440 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14442 while(prevMonth.valueOf() < nextMonth) {
14445 if (prevMonth.getUTCDay() === this.weekStart) {
14447 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14455 if(this.calendarWeeks){
14456 // ISO 8601: First week contains first thursday.
14457 // ISO also states week starts on Monday, but we can be more abstract here.
14459 // Start of current week: based on weekstart/current date
14460 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14461 // Thursday of this week
14462 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14463 // First Thursday of year, year from thursday
14464 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14465 // Calendar week: ms between thursdays, div ms per day, div 7 days
14466 calWeek = (th - yth) / 864e5 / 7 + 1;
14468 fillMonths.cn.push({
14476 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14478 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14481 if (this.todayHighlight &&
14482 prevMonth.getUTCFullYear() == today.getFullYear() &&
14483 prevMonth.getUTCMonth() == today.getMonth() &&
14484 prevMonth.getUTCDate() == today.getDate()) {
14485 clsName += ' today';
14488 if (currentDate && prevMonth.valueOf() === currentDate) {
14489 clsName += ' active';
14492 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14493 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14494 clsName += ' disabled';
14497 fillMonths.cn.push({
14499 cls: 'day ' + clsName,
14500 html: prevMonth.getDate()
14503 prevMonth.setDate(prevMonth.getDate()+1);
14506 var currentYear = this.date && this.date.getUTCFullYear();
14507 var currentMonth = this.date && this.date.getUTCMonth();
14509 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14511 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14512 v.removeClass('active');
14514 if(currentYear === year && k === currentMonth){
14515 v.addClass('active');
14518 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14519 v.addClass('disabled');
14525 year = parseInt(year/10, 10) * 10;
14527 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14529 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14532 for (var i = -1; i < 11; i++) {
14533 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14535 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14543 showMode: function(dir)
14546 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14548 Roo.each(this.picker().select('>div',true).elements, function(v){
14549 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14552 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14557 if(this.isInline) return;
14559 this.picker().removeClass(['bottom', 'top']);
14561 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14563 * place to the top of element!
14567 this.picker().addClass('top');
14568 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14573 this.picker().addClass('bottom');
14575 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14578 parseDate : function(value)
14580 if(!value || value instanceof Date){
14583 var v = Date.parseDate(value, this.format);
14584 if (!v && this.useIso) {
14585 v = Date.parseDate(value, 'Y-m-d');
14587 if(!v && this.altFormats){
14588 if(!this.altFormatsArray){
14589 this.altFormatsArray = this.altFormats.split("|");
14591 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14592 v = Date.parseDate(value, this.altFormatsArray[i]);
14598 formatDate : function(date, fmt)
14600 return (!date || !(date instanceof Date)) ?
14601 date : date.dateFormat(fmt || this.format);
14604 onFocus : function()
14606 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14610 onBlur : function()
14612 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14614 var d = this.inputEl().getValue();
14625 this.picker().show();
14629 this.fireEvent('show', this, this.date);
14634 if(this.isInline) return;
14635 this.picker().hide();
14636 this.viewMode = this.startViewMode;
14639 this.fireEvent('hide', this, this.date);
14643 onMousedown: function(e)
14645 e.stopPropagation();
14646 e.preventDefault();
14651 Roo.bootstrap.DateField.superclass.keyup.call(this);
14655 setValue: function(v)
14657 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14659 var d = new Date(v);
14661 if(isNaN(d.getTime())){
14665 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14669 this.fireEvent('select', this, this.date);
14673 getValue: function()
14675 return this.formatDate(this.date);
14678 fireKey: function(e)
14680 if (!this.picker().isVisible()){
14681 if (e.keyCode == 27) // allow escape to hide and re-show picker
14686 var dateChanged = false,
14688 newDate, newViewDate;
14693 e.preventDefault();
14697 if (!this.keyboardNavigation) break;
14698 dir = e.keyCode == 37 ? -1 : 1;
14701 newDate = this.moveYear(this.date, dir);
14702 newViewDate = this.moveYear(this.viewDate, dir);
14703 } else if (e.shiftKey){
14704 newDate = this.moveMonth(this.date, dir);
14705 newViewDate = this.moveMonth(this.viewDate, dir);
14707 newDate = new Date(this.date);
14708 newDate.setUTCDate(this.date.getUTCDate() + dir);
14709 newViewDate = new Date(this.viewDate);
14710 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14712 if (this.dateWithinRange(newDate)){
14713 this.date = newDate;
14714 this.viewDate = newViewDate;
14715 this.setValue(this.formatDate(this.date));
14717 e.preventDefault();
14718 dateChanged = true;
14723 if (!this.keyboardNavigation) break;
14724 dir = e.keyCode == 38 ? -1 : 1;
14726 newDate = this.moveYear(this.date, dir);
14727 newViewDate = this.moveYear(this.viewDate, dir);
14728 } else if (e.shiftKey){
14729 newDate = this.moveMonth(this.date, dir);
14730 newViewDate = this.moveMonth(this.viewDate, dir);
14732 newDate = new Date(this.date);
14733 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14734 newViewDate = new Date(this.viewDate);
14735 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14737 if (this.dateWithinRange(newDate)){
14738 this.date = newDate;
14739 this.viewDate = newViewDate;
14740 this.setValue(this.formatDate(this.date));
14742 e.preventDefault();
14743 dateChanged = true;
14747 this.setValue(this.formatDate(this.date));
14749 e.preventDefault();
14752 this.setValue(this.formatDate(this.date));
14766 onClick: function(e)
14768 e.stopPropagation();
14769 e.preventDefault();
14771 var target = e.getTarget();
14773 if(target.nodeName.toLowerCase() === 'i'){
14774 target = Roo.get(target).dom.parentNode;
14777 var nodeName = target.nodeName;
14778 var className = target.className;
14779 var html = target.innerHTML;
14781 switch(nodeName.toLowerCase()) {
14783 switch(className) {
14789 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14790 switch(this.viewMode){
14792 this.viewDate = this.moveMonth(this.viewDate, dir);
14796 this.viewDate = this.moveYear(this.viewDate, dir);
14802 var date = new Date();
14803 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14805 this.setValue(this.formatDate(this.date));
14812 if (className.indexOf('disabled') === -1) {
14813 this.viewDate.setUTCDate(1);
14814 if (className.indexOf('month') !== -1) {
14815 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14817 var year = parseInt(html, 10) || 0;
14818 this.viewDate.setUTCFullYear(year);
14827 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14828 var day = parseInt(html, 10) || 1;
14829 var year = this.viewDate.getUTCFullYear(),
14830 month = this.viewDate.getUTCMonth();
14832 if (className.indexOf('old') !== -1) {
14839 } else if (className.indexOf('new') !== -1) {
14847 this.date = this.UTCDate(year, month, day,0,0,0,0);
14848 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14850 this.setValue(this.formatDate(this.date));
14857 setStartDate: function(startDate)
14859 this.startDate = startDate || -Infinity;
14860 if (this.startDate !== -Infinity) {
14861 this.startDate = this.parseDate(this.startDate);
14864 this.updateNavArrows();
14867 setEndDate: function(endDate)
14869 this.endDate = endDate || Infinity;
14870 if (this.endDate !== Infinity) {
14871 this.endDate = this.parseDate(this.endDate);
14874 this.updateNavArrows();
14877 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14879 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14880 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14881 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14883 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14884 return parseInt(d, 10);
14887 this.updateNavArrows();
14890 updateNavArrows: function()
14892 var d = new Date(this.viewDate),
14893 year = d.getUTCFullYear(),
14894 month = d.getUTCMonth();
14896 Roo.each(this.picker().select('.prev', true).elements, function(v){
14898 switch (this.viewMode) {
14901 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14907 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14914 Roo.each(this.picker().select('.next', true).elements, function(v){
14916 switch (this.viewMode) {
14919 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14925 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14933 moveMonth: function(date, dir)
14935 if (!dir) return date;
14936 var new_date = new Date(date.valueOf()),
14937 day = new_date.getUTCDate(),
14938 month = new_date.getUTCMonth(),
14939 mag = Math.abs(dir),
14941 dir = dir > 0 ? 1 : -1;
14944 // If going back one month, make sure month is not current month
14945 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14947 return new_date.getUTCMonth() == month;
14949 // If going forward one month, make sure month is as expected
14950 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14952 return new_date.getUTCMonth() != new_month;
14954 new_month = month + dir;
14955 new_date.setUTCMonth(new_month);
14956 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14957 if (new_month < 0 || new_month > 11)
14958 new_month = (new_month + 12) % 12;
14960 // For magnitudes >1, move one month at a time...
14961 for (var i=0; i<mag; i++)
14962 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14963 new_date = this.moveMonth(new_date, dir);
14964 // ...then reset the day, keeping it in the new month
14965 new_month = new_date.getUTCMonth();
14966 new_date.setUTCDate(day);
14968 return new_month != new_date.getUTCMonth();
14971 // Common date-resetting loop -- if date is beyond end of month, make it
14974 new_date.setUTCDate(--day);
14975 new_date.setUTCMonth(new_month);
14980 moveYear: function(date, dir)
14982 return this.moveMonth(date, dir*12);
14985 dateWithinRange: function(date)
14987 return date >= this.startDate && date <= this.endDate;
14993 this.picker().remove();
14998 Roo.apply(Roo.bootstrap.DateField, {
15009 html: '<i class="fa fa-arrow-left"/>'
15019 html: '<i class="fa fa-arrow-right"/>'
15061 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15062 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15063 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15064 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15065 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15078 navFnc: 'FullYear',
15083 navFnc: 'FullYear',
15088 Roo.apply(Roo.bootstrap.DateField, {
15092 cls: 'datepicker dropdown-menu',
15096 cls: 'datepicker-days',
15100 cls: 'table-condensed',
15102 Roo.bootstrap.DateField.head,
15106 Roo.bootstrap.DateField.footer
15113 cls: 'datepicker-months',
15117 cls: 'table-condensed',
15119 Roo.bootstrap.DateField.head,
15120 Roo.bootstrap.DateField.content,
15121 Roo.bootstrap.DateField.footer
15128 cls: 'datepicker-years',
15132 cls: 'table-condensed',
15134 Roo.bootstrap.DateField.head,
15135 Roo.bootstrap.DateField.content,
15136 Roo.bootstrap.DateField.footer
15155 * @class Roo.bootstrap.TimeField
15156 * @extends Roo.bootstrap.Input
15157 * Bootstrap DateField class
15161 * Create a new TimeField
15162 * @param {Object} config The config object
15165 Roo.bootstrap.TimeField = function(config){
15166 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15170 * Fires when this field show.
15171 * @param {Roo.bootstrap.DateField} this
15172 * @param {Mixed} date The date value
15177 * Fires when this field hide.
15178 * @param {Roo.bootstrap.DateField} this
15179 * @param {Mixed} date The date value
15184 * Fires when select a date.
15185 * @param {Roo.bootstrap.DateField} this
15186 * @param {Mixed} date The date value
15192 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15195 * @cfg {String} format
15196 * The default time format string which can be overriden for localization support. The format must be
15197 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15201 onRender: function(ct, position)
15204 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15206 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15208 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15210 this.pop = this.picker().select('>.datepicker-time',true).first();
15211 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15213 this.picker().on('mousedown', this.onMousedown, this);
15214 this.picker().on('click', this.onClick, this);
15216 this.picker().addClass('datepicker-dropdown');
15221 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15222 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15223 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15224 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15225 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15226 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15230 fireKey: function(e){
15231 if (!this.picker().isVisible()){
15232 if (e.keyCode == 27) // allow escape to hide and re-show picker
15237 e.preventDefault();
15245 this.onTogglePeriod();
15248 this.onIncrementMinutes();
15251 this.onDecrementMinutes();
15260 onClick: function(e) {
15261 e.stopPropagation();
15262 e.preventDefault();
15265 picker : function()
15267 return this.el.select('.datepicker', true).first();
15270 fillTime: function()
15272 var time = this.pop.select('tbody', true).first();
15274 time.dom.innerHTML = '';
15289 cls: 'hours-up glyphicon glyphicon-chevron-up'
15309 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15330 cls: 'timepicker-hour',
15345 cls: 'timepicker-minute',
15360 cls: 'btn btn-primary period',
15382 cls: 'hours-down glyphicon glyphicon-chevron-down'
15402 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15420 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15427 var hours = this.time.getHours();
15428 var minutes = this.time.getMinutes();
15441 hours = hours - 12;
15445 hours = '0' + hours;
15449 minutes = '0' + minutes;
15452 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15453 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15454 this.pop.select('button', true).first().dom.innerHTML = period;
15460 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15462 var cls = ['bottom'];
15464 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15471 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15476 this.picker().addClass(cls.join('-'));
15480 Roo.each(cls, function(c){
15482 _this.picker().setTop(_this.inputEl().getHeight());
15486 _this.picker().setTop(0 - _this.picker().getHeight());
15491 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15495 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15502 onFocus : function()
15504 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15508 onBlur : function()
15510 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15516 this.picker().show();
15521 this.fireEvent('show', this, this.date);
15526 this.picker().hide();
15529 this.fireEvent('hide', this, this.date);
15532 setTime : function()
15535 this.setValue(this.time.format(this.format));
15537 this.fireEvent('select', this, this.date);
15542 onMousedown: function(e){
15543 e.stopPropagation();
15544 e.preventDefault();
15547 onIncrementHours: function()
15549 Roo.log('onIncrementHours');
15550 this.time = this.time.add(Date.HOUR, 1);
15555 onDecrementHours: function()
15557 Roo.log('onDecrementHours');
15558 this.time = this.time.add(Date.HOUR, -1);
15562 onIncrementMinutes: function()
15564 Roo.log('onIncrementMinutes');
15565 this.time = this.time.add(Date.MINUTE, 1);
15569 onDecrementMinutes: function()
15571 Roo.log('onDecrementMinutes');
15572 this.time = this.time.add(Date.MINUTE, -1);
15576 onTogglePeriod: function()
15578 Roo.log('onTogglePeriod');
15579 this.time = this.time.add(Date.HOUR, 12);
15586 Roo.apply(Roo.bootstrap.TimeField, {
15616 cls: 'btn btn-info ok',
15628 Roo.apply(Roo.bootstrap.TimeField, {
15632 cls: 'datepicker dropdown-menu',
15636 cls: 'datepicker-time',
15640 cls: 'table-condensed',
15642 Roo.bootstrap.TimeField.content,
15643 Roo.bootstrap.TimeField.footer
15662 * @class Roo.bootstrap.CheckBox
15663 * @extends Roo.bootstrap.Input
15664 * Bootstrap CheckBox class
15666 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15667 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15668 * @cfg {String} boxLabel The text that appears beside the checkbox
15669 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15670 * @cfg {Boolean} checked initnal the element
15674 * Create a new CheckBox
15675 * @param {Object} config The config object
15678 Roo.bootstrap.CheckBox = function(config){
15679 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15684 * Fires when the element is checked or unchecked.
15685 * @param {Roo.bootstrap.CheckBox} this This input
15686 * @param {Boolean} checked The new checked value
15692 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15694 inputType: 'checkbox',
15701 getAutoCreate : function()
15703 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15709 cfg.cls = 'form-group checkbox' //input-group
15717 type : this.inputType,
15718 value : (!this.checked) ? this.valueOff : this.inputValue,
15719 cls : 'roo-checkbox', //'form-box',
15720 placeholder : this.placeholder || ''
15724 if (this.weight) { // Validity check?
15725 cfg.cls += " checkbox-" + this.weight;
15728 if (this.disabled) {
15729 input.disabled=true;
15733 input.checked = this.checked;
15737 input.name = this.name;
15741 input.cls += ' input-' + this.size;
15745 ['xs','sm','md','lg'].map(function(size){
15746 if (settings[size]) {
15747 cfg.cls += ' col-' + size + '-' + settings[size];
15753 var inputblock = input;
15758 if (this.before || this.after) {
15761 cls : 'input-group',
15765 inputblock.cn.push({
15767 cls : 'input-group-addon',
15771 inputblock.cn.push(input);
15773 inputblock.cn.push({
15775 cls : 'input-group-addon',
15782 if (align ==='left' && this.fieldLabel.length) {
15783 Roo.log("left and has label");
15789 cls : 'control-label col-md-' + this.labelWidth,
15790 html : this.fieldLabel
15794 cls : "col-md-" + (12 - this.labelWidth),
15801 } else if ( this.fieldLabel.length) {
15806 tag: this.boxLabel ? 'span' : 'label',
15808 cls: 'control-label box-input-label',
15809 //cls : 'input-group-addon',
15810 html : this.fieldLabel
15820 Roo.log(" no label && no align");
15821 cfg.cn = [ inputblock ] ;
15830 html: this.boxLabel
15842 * return the real input element.
15844 inputEl: function ()
15846 return this.el.select('input.roo-checkbox',true).first();
15851 return this.el.select('label.control-label',true).first();
15854 initEvents : function()
15856 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15858 this.inputEl().on('click', this.onClick, this);
15862 onClick : function()
15864 this.setChecked(!this.checked);
15867 setChecked : function(state,suppressEvent)
15869 this.checked = state;
15871 this.inputEl().dom.checked = state;
15873 if(suppressEvent !== true){
15874 this.fireEvent('check', this, state);
15877 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15881 setValue : function(v,suppressEvent)
15883 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15897 * @class Roo.bootstrap.Radio
15898 * @extends Roo.bootstrap.CheckBox
15899 * Bootstrap Radio class
15902 * Create a new Radio
15903 * @param {Object} config The config object
15906 Roo.bootstrap.Radio = function(config){
15907 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15911 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15913 inputType: 'radio',
15917 getAutoCreate : function()
15919 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15925 cfg.cls = 'form-group radio' //input-group
15930 type : this.inputType,
15931 value : (!this.checked) ? this.valueOff : this.inputValue,
15933 placeholder : this.placeholder || ''
15936 if (this.weight) { // Validity check?
15937 cfg.cls += " radio-" + this.weight;
15939 if (this.disabled) {
15940 input.disabled=true;
15944 input.checked = this.checked;
15948 input.name = this.name;
15952 input.cls += ' input-' + this.size;
15956 ['xs','sm','md','lg'].map(function(size){
15957 if (settings[size]) {
15958 cfg.cls += ' col-' + size + '-' + settings[size];
15962 var inputblock = input;
15964 if (this.before || this.after) {
15967 cls : 'input-group',
15971 inputblock.cn.push({
15973 cls : 'input-group-addon',
15977 inputblock.cn.push(input);
15979 inputblock.cn.push({
15981 cls : 'input-group-addon',
15988 if (align ==='left' && this.fieldLabel.length) {
15989 Roo.log("left and has label");
15995 cls : 'control-label col-md-' + this.labelWidth,
15996 html : this.fieldLabel
16000 cls : "col-md-" + (12 - this.labelWidth),
16007 } else if ( this.fieldLabel.length) {
16014 cls: 'control-label box-input-label',
16015 //cls : 'input-group-addon',
16016 html : this.fieldLabel
16026 Roo.log(" no label && no align");
16041 html: this.boxLabel
16048 inputEl: function ()
16050 return this.el.select('input.roo-radio',true).first();
16052 onClick : function()
16054 this.setChecked(true);
16057 setChecked : function(state,suppressEvent)
16060 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16061 v.dom.checked = false;
16065 this.checked = state;
16066 this.inputEl().dom.checked = state;
16068 if(suppressEvent !== true){
16069 this.fireEvent('check', this, state);
16072 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16076 getGroupValue : function()
16079 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16080 if(v.dom.checked == true){
16081 value = v.dom.value;
16089 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16090 * @return {Mixed} value The field value
16092 getValue : function(){
16093 return this.getGroupValue();
16099 //<script type="text/javascript">
16102 * Based Ext JS Library 1.1.1
16103 * Copyright(c) 2006-2007, Ext JS, LLC.
16109 * @class Roo.HtmlEditorCore
16110 * @extends Roo.Component
16111 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16113 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16116 Roo.HtmlEditorCore = function(config){
16119 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16122 * @event initialize
16123 * Fires when the editor is fully initialized (including the iframe)
16124 * @param {Roo.HtmlEditorCore} this
16129 * Fires when the editor is first receives the focus. Any insertion must wait
16130 * until after this event.
16131 * @param {Roo.HtmlEditorCore} this
16135 * @event beforesync
16136 * Fires before the textarea is updated with content from the editor iframe. Return false
16137 * to cancel the sync.
16138 * @param {Roo.HtmlEditorCore} this
16139 * @param {String} html
16143 * @event beforepush
16144 * Fires before the iframe editor is updated with content from the textarea. Return false
16145 * to cancel the push.
16146 * @param {Roo.HtmlEditorCore} this
16147 * @param {String} html
16152 * Fires when the textarea is updated with content from the editor iframe.
16153 * @param {Roo.HtmlEditorCore} this
16154 * @param {String} html
16159 * Fires when the iframe editor is updated with content from the textarea.
16160 * @param {Roo.HtmlEditorCore} this
16161 * @param {String} html
16166 * @event editorevent
16167 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16168 * @param {Roo.HtmlEditorCore} this
16176 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16180 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16186 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16191 * @cfg {Number} height (in pixels)
16195 * @cfg {Number} width (in pixels)
16200 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16203 stylesheets: false,
16208 // private properties
16209 validationEvent : false,
16211 initialized : false,
16213 sourceEditMode : false,
16214 onFocus : Roo.emptyFn,
16216 hideMode:'offsets',
16224 * Protected method that will not generally be called directly. It
16225 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16226 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16228 getDocMarkup : function(){
16231 Roo.log(this.stylesheets);
16233 // inherit styels from page...??
16234 if (this.stylesheets === false) {
16236 Roo.get(document.head).select('style').each(function(node) {
16237 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16240 Roo.get(document.head).select('link').each(function(node) {
16241 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16244 } else if (!this.stylesheets.length) {
16246 st = '<style type="text/css">' +
16247 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16250 Roo.each(this.stylesheets, function(s) {
16251 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16256 st += '<style type="text/css">' +
16257 'IMG { cursor: pointer } ' +
16261 return '<html><head>' + st +
16262 //<style type="text/css">' +
16263 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16265 ' </head><body class="roo-htmleditor-body"></body></html>';
16269 onRender : function(ct, position)
16272 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16273 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16276 this.el.dom.style.border = '0 none';
16277 this.el.dom.setAttribute('tabIndex', -1);
16278 this.el.addClass('x-hidden hide');
16282 if(Roo.isIE){ // fix IE 1px bogus margin
16283 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16287 this.frameId = Roo.id();
16291 var iframe = this.owner.wrap.createChild({
16293 cls: 'form-control', // bootstrap..
16295 name: this.frameId,
16296 frameBorder : 'no',
16297 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16302 this.iframe = iframe.dom;
16304 this.assignDocWin();
16306 this.doc.designMode = 'on';
16309 this.doc.write(this.getDocMarkup());
16313 var task = { // must defer to wait for browser to be ready
16315 //console.log("run task?" + this.doc.readyState);
16316 this.assignDocWin();
16317 if(this.doc.body || this.doc.readyState == 'complete'){
16319 this.doc.designMode="on";
16323 Roo.TaskMgr.stop(task);
16324 this.initEditor.defer(10, this);
16331 Roo.TaskMgr.start(task);
16338 onResize : function(w, h)
16340 Roo.log('resize: ' +w + ',' + h );
16341 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16345 if(typeof w == 'number'){
16347 this.iframe.style.width = w + 'px';
16349 if(typeof h == 'number'){
16351 this.iframe.style.height = h + 'px';
16353 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16360 * Toggles the editor between standard and source edit mode.
16361 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16363 toggleSourceEdit : function(sourceEditMode){
16365 this.sourceEditMode = sourceEditMode === true;
16367 if(this.sourceEditMode){
16369 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16372 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16373 //this.iframe.className = '';
16376 //this.setSize(this.owner.wrap.getSize());
16377 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16384 * Protected method that will not generally be called directly. If you need/want
16385 * custom HTML cleanup, this is the method you should override.
16386 * @param {String} html The HTML to be cleaned
16387 * return {String} The cleaned HTML
16389 cleanHtml : function(html){
16390 html = String(html);
16391 if(html.length > 5){
16392 if(Roo.isSafari){ // strip safari nonsense
16393 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16396 if(html == ' '){
16403 * HTML Editor -> Textarea
16404 * Protected method that will not generally be called directly. Syncs the contents
16405 * of the editor iframe with the textarea.
16407 syncValue : function(){
16408 if(this.initialized){
16409 var bd = (this.doc.body || this.doc.documentElement);
16410 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16411 var html = bd.innerHTML;
16413 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16414 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16416 html = '<div style="'+m[0]+'">' + html + '</div>';
16419 html = this.cleanHtml(html);
16420 // fix up the special chars.. normaly like back quotes in word...
16421 // however we do not want to do this with chinese..
16422 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16423 var cc = b.charCodeAt();
16425 (cc >= 0x4E00 && cc < 0xA000 ) ||
16426 (cc >= 0x3400 && cc < 0x4E00 ) ||
16427 (cc >= 0xf900 && cc < 0xfb00 )
16433 if(this.owner.fireEvent('beforesync', this, html) !== false){
16434 this.el.dom.value = html;
16435 this.owner.fireEvent('sync', this, html);
16441 * Protected method that will not generally be called directly. Pushes the value of the textarea
16442 * into the iframe editor.
16444 pushValue : function(){
16445 if(this.initialized){
16446 var v = this.el.dom.value.trim();
16448 // if(v.length < 1){
16452 if(this.owner.fireEvent('beforepush', this, v) !== false){
16453 var d = (this.doc.body || this.doc.documentElement);
16455 this.cleanUpPaste();
16456 this.el.dom.value = d.innerHTML;
16457 this.owner.fireEvent('push', this, v);
16463 deferFocus : function(){
16464 this.focus.defer(10, this);
16468 focus : function(){
16469 if(this.win && !this.sourceEditMode){
16476 assignDocWin: function()
16478 var iframe = this.iframe;
16481 this.doc = iframe.contentWindow.document;
16482 this.win = iframe.contentWindow;
16484 if (!Roo.get(this.frameId)) {
16487 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16488 this.win = Roo.get(this.frameId).dom.contentWindow;
16493 initEditor : function(){
16494 //console.log("INIT EDITOR");
16495 this.assignDocWin();
16499 this.doc.designMode="on";
16501 this.doc.write(this.getDocMarkup());
16504 var dbody = (this.doc.body || this.doc.documentElement);
16505 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16506 // this copies styles from the containing element into thsi one..
16507 // not sure why we need all of this..
16508 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16510 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16511 //ss['background-attachment'] = 'fixed'; // w3c
16512 dbody.bgProperties = 'fixed'; // ie
16513 //Roo.DomHelper.applyStyles(dbody, ss);
16514 Roo.EventManager.on(this.doc, {
16515 //'mousedown': this.onEditorEvent,
16516 'mouseup': this.onEditorEvent,
16517 'dblclick': this.onEditorEvent,
16518 'click': this.onEditorEvent,
16519 'keyup': this.onEditorEvent,
16524 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16526 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16527 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16529 this.initialized = true;
16531 this.owner.fireEvent('initialize', this);
16536 onDestroy : function(){
16542 //for (var i =0; i < this.toolbars.length;i++) {
16543 // // fixme - ask toolbars for heights?
16544 // this.toolbars[i].onDestroy();
16547 //this.wrap.dom.innerHTML = '';
16548 //this.wrap.remove();
16553 onFirstFocus : function(){
16555 this.assignDocWin();
16558 this.activated = true;
16561 if(Roo.isGecko){ // prevent silly gecko errors
16563 var s = this.win.getSelection();
16564 if(!s.focusNode || s.focusNode.nodeType != 3){
16565 var r = s.getRangeAt(0);
16566 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16571 this.execCmd('useCSS', true);
16572 this.execCmd('styleWithCSS', false);
16575 this.owner.fireEvent('activate', this);
16579 adjustFont: function(btn){
16580 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16581 //if(Roo.isSafari){ // safari
16584 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16585 if(Roo.isSafari){ // safari
16586 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16587 v = (v < 10) ? 10 : v;
16588 v = (v > 48) ? 48 : v;
16589 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16594 v = Math.max(1, v+adjust);
16596 this.execCmd('FontSize', v );
16599 onEditorEvent : function(e){
16600 this.owner.fireEvent('editorevent', this, e);
16601 // this.updateToolbar();
16602 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16605 insertTag : function(tg)
16607 // could be a bit smarter... -> wrap the current selected tRoo..
16608 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16610 range = this.createRange(this.getSelection());
16611 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16612 wrappingNode.appendChild(range.extractContents());
16613 range.insertNode(wrappingNode);
16620 this.execCmd("formatblock", tg);
16624 insertText : function(txt)
16628 var range = this.createRange();
16629 range.deleteContents();
16630 //alert(Sender.getAttribute('label'));
16632 range.insertNode(this.doc.createTextNode(txt));
16638 * Executes a Midas editor command on the editor document and performs necessary focus and
16639 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16640 * @param {String} cmd The Midas command
16641 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16643 relayCmd : function(cmd, value){
16645 this.execCmd(cmd, value);
16646 this.owner.fireEvent('editorevent', this);
16647 //this.updateToolbar();
16648 this.owner.deferFocus();
16652 * Executes a Midas editor command directly on the editor document.
16653 * For visual commands, you should use {@link #relayCmd} instead.
16654 * <b>This should only be called after the editor is initialized.</b>
16655 * @param {String} cmd The Midas command
16656 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16658 execCmd : function(cmd, value){
16659 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16666 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16668 * @param {String} text | dom node..
16670 insertAtCursor : function(text)
16675 if(!this.activated){
16681 var r = this.doc.selection.createRange();
16692 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16696 // from jquery ui (MIT licenced)
16698 var win = this.win;
16700 if (win.getSelection && win.getSelection().getRangeAt) {
16701 range = win.getSelection().getRangeAt(0);
16702 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16703 range.insertNode(node);
16704 } else if (win.document.selection && win.document.selection.createRange) {
16705 // no firefox support
16706 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16707 win.document.selection.createRange().pasteHTML(txt);
16709 // no firefox support
16710 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16711 this.execCmd('InsertHTML', txt);
16720 mozKeyPress : function(e){
16722 var c = e.getCharCode(), cmd;
16725 c = String.fromCharCode(c).toLowerCase();
16739 this.cleanUpPaste.defer(100, this);
16747 e.preventDefault();
16755 fixKeys : function(){ // load time branching for fastest keydown performance
16757 return function(e){
16758 var k = e.getKey(), r;
16761 r = this.doc.selection.createRange();
16764 r.pasteHTML('    ');
16771 r = this.doc.selection.createRange();
16773 var target = r.parentElement();
16774 if(!target || target.tagName.toLowerCase() != 'li'){
16776 r.pasteHTML('<br />');
16782 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16783 this.cleanUpPaste.defer(100, this);
16789 }else if(Roo.isOpera){
16790 return function(e){
16791 var k = e.getKey();
16795 this.execCmd('InsertHTML','    ');
16798 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16799 this.cleanUpPaste.defer(100, this);
16804 }else if(Roo.isSafari){
16805 return function(e){
16806 var k = e.getKey();
16810 this.execCmd('InsertText','\t');
16814 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16815 this.cleanUpPaste.defer(100, this);
16823 getAllAncestors: function()
16825 var p = this.getSelectedNode();
16828 a.push(p); // push blank onto stack..
16829 p = this.getParentElement();
16833 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16837 a.push(this.doc.body);
16841 lastSelNode : false,
16844 getSelection : function()
16846 this.assignDocWin();
16847 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16850 getSelectedNode: function()
16852 // this may only work on Gecko!!!
16854 // should we cache this!!!!
16859 var range = this.createRange(this.getSelection()).cloneRange();
16862 var parent = range.parentElement();
16864 var testRange = range.duplicate();
16865 testRange.moveToElementText(parent);
16866 if (testRange.inRange(range)) {
16869 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16872 parent = parent.parentElement;
16877 // is ancestor a text element.
16878 var ac = range.commonAncestorContainer;
16879 if (ac.nodeType == 3) {
16880 ac = ac.parentNode;
16883 var ar = ac.childNodes;
16886 var other_nodes = [];
16887 var has_other_nodes = false;
16888 for (var i=0;i<ar.length;i++) {
16889 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16892 // fullly contained node.
16894 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16899 // probably selected..
16900 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16901 other_nodes.push(ar[i]);
16905 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16910 has_other_nodes = true;
16912 if (!nodes.length && other_nodes.length) {
16913 nodes= other_nodes;
16915 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16921 createRange: function(sel)
16923 // this has strange effects when using with
16924 // top toolbar - not sure if it's a great idea.
16925 //this.editor.contentWindow.focus();
16926 if (typeof sel != "undefined") {
16928 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16930 return this.doc.createRange();
16933 return this.doc.createRange();
16936 getParentElement: function()
16939 this.assignDocWin();
16940 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16942 var range = this.createRange(sel);
16945 var p = range.commonAncestorContainer;
16946 while (p.nodeType == 3) { // text node
16957 * Range intersection.. the hard stuff...
16961 * [ -- selected range --- ]
16965 * if end is before start or hits it. fail.
16966 * if start is after end or hits it fail.
16968 * if either hits (but other is outside. - then it's not
16974 // @see http://www.thismuchiknow.co.uk/?p=64.
16975 rangeIntersectsNode : function(range, node)
16977 var nodeRange = node.ownerDocument.createRange();
16979 nodeRange.selectNode(node);
16981 nodeRange.selectNodeContents(node);
16984 var rangeStartRange = range.cloneRange();
16985 rangeStartRange.collapse(true);
16987 var rangeEndRange = range.cloneRange();
16988 rangeEndRange.collapse(false);
16990 var nodeStartRange = nodeRange.cloneRange();
16991 nodeStartRange.collapse(true);
16993 var nodeEndRange = nodeRange.cloneRange();
16994 nodeEndRange.collapse(false);
16996 return rangeStartRange.compareBoundaryPoints(
16997 Range.START_TO_START, nodeEndRange) == -1 &&
16998 rangeEndRange.compareBoundaryPoints(
16999 Range.START_TO_START, nodeStartRange) == 1;
17003 rangeCompareNode : function(range, node)
17005 var nodeRange = node.ownerDocument.createRange();
17007 nodeRange.selectNode(node);
17009 nodeRange.selectNodeContents(node);
17013 range.collapse(true);
17015 nodeRange.collapse(true);
17017 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17018 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17020 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17022 var nodeIsBefore = ss == 1;
17023 var nodeIsAfter = ee == -1;
17025 if (nodeIsBefore && nodeIsAfter)
17027 if (!nodeIsBefore && nodeIsAfter)
17028 return 1; //right trailed.
17030 if (nodeIsBefore && !nodeIsAfter)
17031 return 2; // left trailed.
17036 // private? - in a new class?
17037 cleanUpPaste : function()
17039 // cleans up the whole document..
17040 Roo.log('cleanuppaste');
17042 this.cleanUpChildren(this.doc.body);
17043 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17044 if (clean != this.doc.body.innerHTML) {
17045 this.doc.body.innerHTML = clean;
17050 cleanWordChars : function(input) {// change the chars to hex code
17051 var he = Roo.HtmlEditorCore;
17053 var output = input;
17054 Roo.each(he.swapCodes, function(sw) {
17055 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17057 output = output.replace(swapper, sw[1]);
17064 cleanUpChildren : function (n)
17066 if (!n.childNodes.length) {
17069 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17070 this.cleanUpChild(n.childNodes[i]);
17077 cleanUpChild : function (node)
17080 //console.log(node);
17081 if (node.nodeName == "#text") {
17082 // clean up silly Windows -- stuff?
17085 if (node.nodeName == "#comment") {
17086 node.parentNode.removeChild(node);
17087 // clean up silly Windows -- stuff?
17091 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17093 node.parentNode.removeChild(node);
17098 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17100 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17101 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17103 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17104 // remove_keep_children = true;
17107 if (remove_keep_children) {
17108 this.cleanUpChildren(node);
17109 // inserts everything just before this node...
17110 while (node.childNodes.length) {
17111 var cn = node.childNodes[0];
17112 node.removeChild(cn);
17113 node.parentNode.insertBefore(cn, node);
17115 node.parentNode.removeChild(node);
17119 if (!node.attributes || !node.attributes.length) {
17120 this.cleanUpChildren(node);
17124 function cleanAttr(n,v)
17127 if (v.match(/^\./) || v.match(/^\//)) {
17130 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17133 if (v.match(/^#/)) {
17136 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17137 node.removeAttribute(n);
17141 function cleanStyle(n,v)
17143 if (v.match(/expression/)) { //XSS?? should we even bother..
17144 node.removeAttribute(n);
17147 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17148 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17151 var parts = v.split(/;/);
17154 Roo.each(parts, function(p) {
17155 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17159 var l = p.split(':').shift().replace(/\s+/g,'');
17160 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17162 if ( cblack.indexOf(l) > -1) {
17163 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17164 //node.removeAttribute(n);
17168 // only allow 'c whitelisted system attributes'
17169 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17170 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17171 //node.removeAttribute(n);
17181 if (clean.length) {
17182 node.setAttribute(n, clean.join(';'));
17184 node.removeAttribute(n);
17190 for (var i = node.attributes.length-1; i > -1 ; i--) {
17191 var a = node.attributes[i];
17194 if (a.name.toLowerCase().substr(0,2)=='on') {
17195 node.removeAttribute(a.name);
17198 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17199 node.removeAttribute(a.name);
17202 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17203 cleanAttr(a.name,a.value); // fixme..
17206 if (a.name == 'style') {
17207 cleanStyle(a.name,a.value);
17210 /// clean up MS crap..
17211 // tecnically this should be a list of valid class'es..
17214 if (a.name == 'class') {
17215 if (a.value.match(/^Mso/)) {
17216 node.className = '';
17219 if (a.value.match(/body/)) {
17220 node.className = '';
17231 this.cleanUpChildren(node);
17236 * Clean up MS wordisms...
17238 cleanWord : function(node)
17241 var cleanWordChildren = function()
17243 if (!node.childNodes.length) {
17246 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17247 _t.cleanWord(node.childNodes[i]);
17253 this.cleanWord(this.doc.body);
17256 if (node.nodeName == "#text") {
17257 // clean up silly Windows -- stuff?
17260 if (node.nodeName == "#comment") {
17261 node.parentNode.removeChild(node);
17262 // clean up silly Windows -- stuff?
17266 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17267 node.parentNode.removeChild(node);
17271 // remove - but keep children..
17272 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17273 while (node.childNodes.length) {
17274 var cn = node.childNodes[0];
17275 node.removeChild(cn);
17276 node.parentNode.insertBefore(cn, node);
17278 node.parentNode.removeChild(node);
17279 cleanWordChildren();
17283 if (node.className.length) {
17285 var cn = node.className.split(/\W+/);
17287 Roo.each(cn, function(cls) {
17288 if (cls.match(/Mso[a-zA-Z]+/)) {
17293 node.className = cna.length ? cna.join(' ') : '';
17295 node.removeAttribute("class");
17299 if (node.hasAttribute("lang")) {
17300 node.removeAttribute("lang");
17303 if (node.hasAttribute("style")) {
17305 var styles = node.getAttribute("style").split(";");
17307 Roo.each(styles, function(s) {
17308 if (!s.match(/:/)) {
17311 var kv = s.split(":");
17312 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17315 // what ever is left... we allow.
17318 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17319 if (!nstyle.length) {
17320 node.removeAttribute('style');
17324 cleanWordChildren();
17328 domToHTML : function(currentElement, depth, nopadtext) {
17330 depth = depth || 0;
17331 nopadtext = nopadtext || false;
17333 if (!currentElement) {
17334 return this.domToHTML(this.doc.body);
17337 //Roo.log(currentElement);
17339 var allText = false;
17340 var nodeName = currentElement.nodeName;
17341 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17343 if (nodeName == '#text') {
17344 return currentElement.nodeValue;
17349 if (nodeName != 'BODY') {
17352 // Prints the node tagName, such as <A>, <IMG>, etc
17355 for(i = 0; i < currentElement.attributes.length;i++) {
17357 var aname = currentElement.attributes.item(i).name;
17358 if (!currentElement.attributes.item(i).value.length) {
17361 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17364 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17373 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17376 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17381 // Traverse the tree
17383 var currentElementChild = currentElement.childNodes.item(i);
17384 var allText = true;
17385 var innerHTML = '';
17387 while (currentElementChild) {
17388 // Formatting code (indent the tree so it looks nice on the screen)
17389 var nopad = nopadtext;
17390 if (lastnode == 'SPAN') {
17394 if (currentElementChild.nodeName == '#text') {
17395 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17396 if (!nopad && toadd.length > 80) {
17397 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17399 innerHTML += toadd;
17402 currentElementChild = currentElement.childNodes.item(i);
17408 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17410 // Recursively traverse the tree structure of the child node
17411 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17412 lastnode = currentElementChild.nodeName;
17414 currentElementChild=currentElement.childNodes.item(i);
17420 // The remaining code is mostly for formatting the tree
17421 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17426 ret+= "</"+tagName+">";
17432 // hide stuff that is not compatible
17446 * @event specialkey
17450 * @cfg {String} fieldClass @hide
17453 * @cfg {String} focusClass @hide
17456 * @cfg {String} autoCreate @hide
17459 * @cfg {String} inputType @hide
17462 * @cfg {String} invalidClass @hide
17465 * @cfg {String} invalidText @hide
17468 * @cfg {String} msgFx @hide
17471 * @cfg {String} validateOnBlur @hide
17475 Roo.HtmlEditorCore.white = [
17476 'area', 'br', 'img', 'input', 'hr', 'wbr',
17478 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17479 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17480 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17481 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17482 'table', 'ul', 'xmp',
17484 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17487 'dir', 'menu', 'ol', 'ul', 'dl',
17493 Roo.HtmlEditorCore.black = [
17494 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17496 'base', 'basefont', 'bgsound', 'blink', 'body',
17497 'frame', 'frameset', 'head', 'html', 'ilayer',
17498 'iframe', 'layer', 'link', 'meta', 'object',
17499 'script', 'style' ,'title', 'xml' // clean later..
17501 Roo.HtmlEditorCore.clean = [
17502 'script', 'style', 'title', 'xml'
17504 Roo.HtmlEditorCore.remove = [
17509 Roo.HtmlEditorCore.ablack = [
17513 Roo.HtmlEditorCore.aclean = [
17514 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17518 Roo.HtmlEditorCore.pwhite= [
17519 'http', 'https', 'mailto'
17522 // white listed style attributes.
17523 Roo.HtmlEditorCore.cwhite= [
17524 // 'text-align', /// default is to allow most things..
17530 // black listed style attributes.
17531 Roo.HtmlEditorCore.cblack= [
17532 // 'font-size' -- this can be set by the project
17536 Roo.HtmlEditorCore.swapCodes =[
17555 * @class Roo.bootstrap.HtmlEditor
17556 * @extends Roo.bootstrap.TextArea
17557 * Bootstrap HtmlEditor class
17560 * Create a new HtmlEditor
17561 * @param {Object} config The config object
17564 Roo.bootstrap.HtmlEditor = function(config){
17565 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17566 if (!this.toolbars) {
17567 this.toolbars = [];
17569 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17572 * @event initialize
17573 * Fires when the editor is fully initialized (including the iframe)
17574 * @param {HtmlEditor} this
17579 * Fires when the editor is first receives the focus. Any insertion must wait
17580 * until after this event.
17581 * @param {HtmlEditor} this
17585 * @event beforesync
17586 * Fires before the textarea is updated with content from the editor iframe. Return false
17587 * to cancel the sync.
17588 * @param {HtmlEditor} this
17589 * @param {String} html
17593 * @event beforepush
17594 * Fires before the iframe editor is updated with content from the textarea. Return false
17595 * to cancel the push.
17596 * @param {HtmlEditor} this
17597 * @param {String} html
17602 * Fires when the textarea is updated with content from the editor iframe.
17603 * @param {HtmlEditor} this
17604 * @param {String} html
17609 * Fires when the iframe editor is updated with content from the textarea.
17610 * @param {HtmlEditor} this
17611 * @param {String} html
17615 * @event editmodechange
17616 * Fires when the editor switches edit modes
17617 * @param {HtmlEditor} this
17618 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17620 editmodechange: true,
17622 * @event editorevent
17623 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17624 * @param {HtmlEditor} this
17628 * @event firstfocus
17629 * Fires when on first focus - needed by toolbars..
17630 * @param {HtmlEditor} this
17635 * Auto save the htmlEditor value as a file into Events
17636 * @param {HtmlEditor} this
17640 * @event savedpreview
17641 * preview the saved version of htmlEditor
17642 * @param {HtmlEditor} this
17649 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17653 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17658 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17663 * @cfg {Number} height (in pixels)
17667 * @cfg {Number} width (in pixels)
17672 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17675 stylesheets: false,
17680 // private properties
17681 validationEvent : false,
17683 initialized : false,
17686 onFocus : Roo.emptyFn,
17688 hideMode:'offsets',
17691 tbContainer : false,
17693 toolbarContainer :function() {
17694 return this.wrap.select('.x-html-editor-tb',true).first();
17698 * Protected method that will not generally be called directly. It
17699 * is called when the editor creates its toolbar. Override this method if you need to
17700 * add custom toolbar buttons.
17701 * @param {HtmlEditor} editor
17703 createToolbar : function(){
17705 Roo.log("create toolbars");
17707 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17708 this.toolbars[0].render(this.toolbarContainer());
17712 // if (!editor.toolbars || !editor.toolbars.length) {
17713 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17716 // for (var i =0 ; i < editor.toolbars.length;i++) {
17717 // editor.toolbars[i] = Roo.factory(
17718 // typeof(editor.toolbars[i]) == 'string' ?
17719 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17720 // Roo.bootstrap.HtmlEditor);
17721 // editor.toolbars[i].init(editor);
17727 onRender : function(ct, position)
17729 // Roo.log("Call onRender: " + this.xtype);
17731 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17733 this.wrap = this.inputEl().wrap({
17734 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17737 this.editorcore.onRender(ct, position);
17739 if (this.resizable) {
17740 this.resizeEl = new Roo.Resizable(this.wrap, {
17744 minHeight : this.height,
17745 height: this.height,
17746 handles : this.resizable,
17749 resize : function(r, w, h) {
17750 _t.onResize(w,h); // -something
17756 this.createToolbar(this);
17759 if(!this.width && this.resizable){
17760 this.setSize(this.wrap.getSize());
17762 if (this.resizeEl) {
17763 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17764 // should trigger onReize..
17770 onResize : function(w, h)
17772 Roo.log('resize: ' +w + ',' + h );
17773 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17777 if(this.inputEl() ){
17778 if(typeof w == 'number'){
17779 var aw = w - this.wrap.getFrameWidth('lr');
17780 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17783 if(typeof h == 'number'){
17784 var tbh = -11; // fixme it needs to tool bar size!
17785 for (var i =0; i < this.toolbars.length;i++) {
17786 // fixme - ask toolbars for heights?
17787 tbh += this.toolbars[i].el.getHeight();
17788 //if (this.toolbars[i].footer) {
17789 // tbh += this.toolbars[i].footer.el.getHeight();
17797 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17798 ah -= 5; // knock a few pixes off for look..
17799 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17803 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17804 this.editorcore.onResize(ew,eh);
17809 * Toggles the editor between standard and source edit mode.
17810 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17812 toggleSourceEdit : function(sourceEditMode)
17814 this.editorcore.toggleSourceEdit(sourceEditMode);
17816 if(this.editorcore.sourceEditMode){
17817 Roo.log('editor - showing textarea');
17820 // Roo.log(this.syncValue());
17822 this.inputEl().removeClass(['hide', 'x-hidden']);
17823 this.inputEl().dom.removeAttribute('tabIndex');
17824 this.inputEl().focus();
17826 Roo.log('editor - hiding textarea');
17828 // Roo.log(this.pushValue());
17831 this.inputEl().addClass(['hide', 'x-hidden']);
17832 this.inputEl().dom.setAttribute('tabIndex', -1);
17833 //this.deferFocus();
17836 if(this.resizable){
17837 this.setSize(this.wrap.getSize());
17840 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17843 // private (for BoxComponent)
17844 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17846 // private (for BoxComponent)
17847 getResizeEl : function(){
17851 // private (for BoxComponent)
17852 getPositionEl : function(){
17857 initEvents : function(){
17858 this.originalValue = this.getValue();
17862 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17865 // markInvalid : Roo.emptyFn,
17867 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17870 // clearInvalid : Roo.emptyFn,
17872 setValue : function(v){
17873 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17874 this.editorcore.pushValue();
17879 deferFocus : function(){
17880 this.focus.defer(10, this);
17884 focus : function(){
17885 this.editorcore.focus();
17891 onDestroy : function(){
17897 for (var i =0; i < this.toolbars.length;i++) {
17898 // fixme - ask toolbars for heights?
17899 this.toolbars[i].onDestroy();
17902 this.wrap.dom.innerHTML = '';
17903 this.wrap.remove();
17908 onFirstFocus : function(){
17909 //Roo.log("onFirstFocus");
17910 this.editorcore.onFirstFocus();
17911 for (var i =0; i < this.toolbars.length;i++) {
17912 this.toolbars[i].onFirstFocus();
17918 syncValue : function()
17920 this.editorcore.syncValue();
17923 pushValue : function()
17925 this.editorcore.pushValue();
17929 // hide stuff that is not compatible
17943 * @event specialkey
17947 * @cfg {String} fieldClass @hide
17950 * @cfg {String} focusClass @hide
17953 * @cfg {String} autoCreate @hide
17956 * @cfg {String} inputType @hide
17959 * @cfg {String} invalidClass @hide
17962 * @cfg {String} invalidText @hide
17965 * @cfg {String} msgFx @hide
17968 * @cfg {String} validateOnBlur @hide
17977 Roo.namespace('Roo.bootstrap.htmleditor');
17979 * @class Roo.bootstrap.HtmlEditorToolbar1
17984 new Roo.bootstrap.HtmlEditor({
17987 new Roo.bootstrap.HtmlEditorToolbar1({
17988 disable : { fonts: 1 , format: 1, ..., ... , ...],
17994 * @cfg {Object} disable List of elements to disable..
17995 * @cfg {Array} btns List of additional buttons.
17999 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18002 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18005 Roo.apply(this, config);
18007 // default disabled, based on 'good practice'..
18008 this.disable = this.disable || {};
18009 Roo.applyIf(this.disable, {
18012 specialElements : true
18014 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18016 this.editor = config.editor;
18017 this.editorcore = config.editor.editorcore;
18019 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18021 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18022 // dont call parent... till later.
18024 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18029 editorcore : false,
18034 "h1","h2","h3","h4","h5","h6",
18036 "abbr", "acronym", "address", "cite", "samp", "var",
18040 onRender : function(ct, position)
18042 // Roo.log("Call onRender: " + this.xtype);
18044 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18046 this.el.dom.style.marginBottom = '0';
18048 var editorcore = this.editorcore;
18049 var editor= this.editor;
18052 var btn = function(id,cmd , toggle, handler){
18054 var event = toggle ? 'toggle' : 'click';
18059 xns: Roo.bootstrap,
18062 enableToggle:toggle !== false,
18064 pressed : toggle ? false : null,
18067 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18068 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18077 xns: Roo.bootstrap,
18078 glyphicon : 'font',
18082 xns: Roo.bootstrap,
18086 Roo.each(this.formats, function(f) {
18087 style.menu.items.push({
18089 xns: Roo.bootstrap,
18090 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18095 editorcore.insertTag(this.tagname);
18102 children.push(style);
18105 btn('bold',false,true);
18106 btn('italic',false,true);
18107 btn('align-left', 'justifyleft',true);
18108 btn('align-center', 'justifycenter',true);
18109 btn('align-right' , 'justifyright',true);
18110 btn('link', false, false, function(btn) {
18111 //Roo.log("create link?");
18112 var url = prompt(this.createLinkText, this.defaultLinkValue);
18113 if(url && url != 'http:/'+'/'){
18114 this.editorcore.relayCmd('createlink', url);
18117 btn('list','insertunorderedlist',true);
18118 btn('pencil', false,true, function(btn){
18121 this.toggleSourceEdit(btn.pressed);
18127 xns: Roo.bootstrap,
18132 xns: Roo.bootstrap,
18137 cog.menu.items.push({
18139 xns: Roo.bootstrap,
18140 html : Clean styles,
18145 editorcore.insertTag(this.tagname);
18154 this.xtype = 'NavSimplebar';
18156 for(var i=0;i< children.length;i++) {
18158 this.buttons.add(this.addxtypeChild(children[i]));
18162 editor.on('editorevent', this.updateToolbar, this);
18164 onBtnClick : function(id)
18166 this.editorcore.relayCmd(id);
18167 this.editorcore.focus();
18171 * Protected method that will not generally be called directly. It triggers
18172 * a toolbar update by reading the markup state of the current selection in the editor.
18174 updateToolbar: function(){
18176 if(!this.editorcore.activated){
18177 this.editor.onFirstFocus(); // is this neeed?
18181 var btns = this.buttons;
18182 var doc = this.editorcore.doc;
18183 btns.get('bold').setActive(doc.queryCommandState('bold'));
18184 btns.get('italic').setActive(doc.queryCommandState('italic'));
18185 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18187 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18188 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18189 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18191 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18192 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18195 var ans = this.editorcore.getAllAncestors();
18196 if (this.formatCombo) {
18199 var store = this.formatCombo.store;
18200 this.formatCombo.setValue("");
18201 for (var i =0; i < ans.length;i++) {
18202 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18204 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18212 // hides menus... - so this cant be on a menu...
18213 Roo.bootstrap.MenuMgr.hideAll();
18215 Roo.bootstrap.MenuMgr.hideAll();
18216 //this.editorsyncValue();
18218 onFirstFocus: function() {
18219 this.buttons.each(function(item){
18223 toggleSourceEdit : function(sourceEditMode){
18226 if(sourceEditMode){
18227 Roo.log("disabling buttons");
18228 this.buttons.each( function(item){
18229 if(item.cmd != 'pencil'){
18235 Roo.log("enabling buttons");
18236 if(this.editorcore.initialized){
18237 this.buttons.each( function(item){
18243 Roo.log("calling toggole on editor");
18244 // tell the editor that it's been pressed..
18245 this.editor.toggleSourceEdit(sourceEditMode);
18255 * @class Roo.bootstrap.Table.AbstractSelectionModel
18256 * @extends Roo.util.Observable
18257 * Abstract base class for grid SelectionModels. It provides the interface that should be
18258 * implemented by descendant classes. This class should not be directly instantiated.
18261 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18262 this.locked = false;
18263 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18267 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18268 /** @ignore Called by the grid automatically. Do not call directly. */
18269 init : function(grid){
18275 * Locks the selections.
18278 this.locked = true;
18282 * Unlocks the selections.
18284 unlock : function(){
18285 this.locked = false;
18289 * Returns true if the selections are locked.
18290 * @return {Boolean}
18292 isLocked : function(){
18293 return this.locked;
18297 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18298 * @class Roo.bootstrap.Table.RowSelectionModel
18299 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18300 * It supports multiple selections and keyboard selection/navigation.
18302 * @param {Object} config
18305 Roo.bootstrap.Table.RowSelectionModel = function(config){
18306 Roo.apply(this, config);
18307 this.selections = new Roo.util.MixedCollection(false, function(o){
18312 this.lastActive = false;
18316 * @event selectionchange
18317 * Fires when the selection changes
18318 * @param {SelectionModel} this
18320 "selectionchange" : true,
18322 * @event afterselectionchange
18323 * Fires after the selection changes (eg. by key press or clicking)
18324 * @param {SelectionModel} this
18326 "afterselectionchange" : true,
18328 * @event beforerowselect
18329 * Fires when a row is selected being selected, return false to cancel.
18330 * @param {SelectionModel} this
18331 * @param {Number} rowIndex The selected index
18332 * @param {Boolean} keepExisting False if other selections will be cleared
18334 "beforerowselect" : true,
18337 * Fires when a row is selected.
18338 * @param {SelectionModel} this
18339 * @param {Number} rowIndex The selected index
18340 * @param {Roo.data.Record} r The record
18342 "rowselect" : true,
18344 * @event rowdeselect
18345 * Fires when a row is deselected.
18346 * @param {SelectionModel} this
18347 * @param {Number} rowIndex The selected index
18349 "rowdeselect" : true
18351 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18352 this.locked = false;
18355 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18357 * @cfg {Boolean} singleSelect
18358 * True to allow selection of only one row at a time (defaults to false)
18360 singleSelect : false,
18363 initEvents : function(){
18365 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18366 this.grid.on("mousedown", this.handleMouseDown, this);
18367 }else{ // allow click to work like normal
18368 this.grid.on("rowclick", this.handleDragableRowClick, this);
18371 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18372 "up" : function(e){
18374 this.selectPrevious(e.shiftKey);
18375 }else if(this.last !== false && this.lastActive !== false){
18376 var last = this.last;
18377 this.selectRange(this.last, this.lastActive-1);
18378 this.grid.getView().focusRow(this.lastActive);
18379 if(last !== false){
18383 this.selectFirstRow();
18385 this.fireEvent("afterselectionchange", this);
18387 "down" : function(e){
18389 this.selectNext(e.shiftKey);
18390 }else if(this.last !== false && this.lastActive !== false){
18391 var last = this.last;
18392 this.selectRange(this.last, this.lastActive+1);
18393 this.grid.getView().focusRow(this.lastActive);
18394 if(last !== false){
18398 this.selectFirstRow();
18400 this.fireEvent("afterselectionchange", this);
18405 var view = this.grid.view;
18406 view.on("refresh", this.onRefresh, this);
18407 view.on("rowupdated", this.onRowUpdated, this);
18408 view.on("rowremoved", this.onRemove, this);
18412 onRefresh : function(){
18413 var ds = this.grid.dataSource, i, v = this.grid.view;
18414 var s = this.selections;
18415 s.each(function(r){
18416 if((i = ds.indexOfId(r.id)) != -1){
18425 onRemove : function(v, index, r){
18426 this.selections.remove(r);
18430 onRowUpdated : function(v, index, r){
18431 if(this.isSelected(r)){
18432 v.onRowSelect(index);
18438 * @param {Array} records The records to select
18439 * @param {Boolean} keepExisting (optional) True to keep existing selections
18441 selectRecords : function(records, keepExisting){
18443 this.clearSelections();
18445 var ds = this.grid.dataSource;
18446 for(var i = 0, len = records.length; i < len; i++){
18447 this.selectRow(ds.indexOf(records[i]), true);
18452 * Gets the number of selected rows.
18455 getCount : function(){
18456 return this.selections.length;
18460 * Selects the first row in the grid.
18462 selectFirstRow : function(){
18467 * Select the last row.
18468 * @param {Boolean} keepExisting (optional) True to keep existing selections
18470 selectLastRow : function(keepExisting){
18471 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18475 * Selects the row immediately following the last selected row.
18476 * @param {Boolean} keepExisting (optional) True to keep existing selections
18478 selectNext : function(keepExisting){
18479 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18480 this.selectRow(this.last+1, keepExisting);
18481 this.grid.getView().focusRow(this.last);
18486 * Selects the row that precedes the last selected row.
18487 * @param {Boolean} keepExisting (optional) True to keep existing selections
18489 selectPrevious : function(keepExisting){
18491 this.selectRow(this.last-1, keepExisting);
18492 this.grid.getView().focusRow(this.last);
18497 * Returns the selected records
18498 * @return {Array} Array of selected records
18500 getSelections : function(){
18501 return [].concat(this.selections.items);
18505 * Returns the first selected record.
18508 getSelected : function(){
18509 return this.selections.itemAt(0);
18514 * Clears all selections.
18516 clearSelections : function(fast){
18517 if(this.locked) return;
18519 var ds = this.grid.dataSource;
18520 var s = this.selections;
18521 s.each(function(r){
18522 this.deselectRow(ds.indexOfId(r.id));
18526 this.selections.clear();
18533 * Selects all rows.
18535 selectAll : function(){
18536 if(this.locked) return;
18537 this.selections.clear();
18538 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18539 this.selectRow(i, true);
18544 * Returns True if there is a selection.
18545 * @return {Boolean}
18547 hasSelection : function(){
18548 return this.selections.length > 0;
18552 * Returns True if the specified row is selected.
18553 * @param {Number/Record} record The record or index of the record to check
18554 * @return {Boolean}
18556 isSelected : function(index){
18557 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18558 return (r && this.selections.key(r.id) ? true : false);
18562 * Returns True if the specified record id is selected.
18563 * @param {String} id The id of record to check
18564 * @return {Boolean}
18566 isIdSelected : function(id){
18567 return (this.selections.key(id) ? true : false);
18571 handleMouseDown : function(e, t){
18572 var view = this.grid.getView(), rowIndex;
18573 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18576 if(e.shiftKey && this.last !== false){
18577 var last = this.last;
18578 this.selectRange(last, rowIndex, e.ctrlKey);
18579 this.last = last; // reset the last
18580 view.focusRow(rowIndex);
18582 var isSelected = this.isSelected(rowIndex);
18583 if(e.button !== 0 && isSelected){
18584 view.focusRow(rowIndex);
18585 }else if(e.ctrlKey && isSelected){
18586 this.deselectRow(rowIndex);
18587 }else if(!isSelected){
18588 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18589 view.focusRow(rowIndex);
18592 this.fireEvent("afterselectionchange", this);
18595 handleDragableRowClick : function(grid, rowIndex, e)
18597 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18598 this.selectRow(rowIndex, false);
18599 grid.view.focusRow(rowIndex);
18600 this.fireEvent("afterselectionchange", this);
18605 * Selects multiple rows.
18606 * @param {Array} rows Array of the indexes of the row to select
18607 * @param {Boolean} keepExisting (optional) True to keep existing selections
18609 selectRows : function(rows, keepExisting){
18611 this.clearSelections();
18613 for(var i = 0, len = rows.length; i < len; i++){
18614 this.selectRow(rows[i], true);
18619 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18620 * @param {Number} startRow The index of the first row in the range
18621 * @param {Number} endRow The index of the last row in the range
18622 * @param {Boolean} keepExisting (optional) True to retain existing selections
18624 selectRange : function(startRow, endRow, keepExisting){
18625 if(this.locked) return;
18627 this.clearSelections();
18629 if(startRow <= endRow){
18630 for(var i = startRow; i <= endRow; i++){
18631 this.selectRow(i, true);
18634 for(var i = startRow; i >= endRow; i--){
18635 this.selectRow(i, true);
18641 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18642 * @param {Number} startRow The index of the first row in the range
18643 * @param {Number} endRow The index of the last row in the range
18645 deselectRange : function(startRow, endRow, preventViewNotify){
18646 if(this.locked) return;
18647 for(var i = startRow; i <= endRow; i++){
18648 this.deselectRow(i, preventViewNotify);
18654 * @param {Number} row The index of the row to select
18655 * @param {Boolean} keepExisting (optional) True to keep existing selections
18657 selectRow : function(index, keepExisting, preventViewNotify){
18658 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18659 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18660 if(!keepExisting || this.singleSelect){
18661 this.clearSelections();
18663 var r = this.grid.dataSource.getAt(index);
18664 this.selections.add(r);
18665 this.last = this.lastActive = index;
18666 if(!preventViewNotify){
18667 this.grid.getView().onRowSelect(index);
18669 this.fireEvent("rowselect", this, index, r);
18670 this.fireEvent("selectionchange", this);
18676 * @param {Number} row The index of the row to deselect
18678 deselectRow : function(index, preventViewNotify){
18679 if(this.locked) return;
18680 if(this.last == index){
18683 if(this.lastActive == index){
18684 this.lastActive = false;
18686 var r = this.grid.dataSource.getAt(index);
18687 this.selections.remove(r);
18688 if(!preventViewNotify){
18689 this.grid.getView().onRowDeselect(index);
18691 this.fireEvent("rowdeselect", this, index);
18692 this.fireEvent("selectionchange", this);
18696 restoreLast : function(){
18698 this.last = this._last;
18703 acceptsNav : function(row, col, cm){
18704 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18708 onEditorKey : function(field, e){
18709 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18714 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18716 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18718 }else if(k == e.ENTER && !e.ctrlKey){
18722 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18724 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18726 }else if(k == e.ESC){
18730 g.startEditing(newCell[0], newCell[1]);
18735 * Ext JS Library 1.1.1
18736 * Copyright(c) 2006-2007, Ext JS, LLC.
18738 * Originally Released Under LGPL - original licence link has changed is not relivant.
18741 * <script type="text/javascript">
18745 * @class Roo.bootstrap.PagingToolbar
18747 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18749 * Create a new PagingToolbar
18750 * @param {Object} config The config object
18752 Roo.bootstrap.PagingToolbar = function(config)
18754 // old args format still supported... - xtype is prefered..
18755 // created from xtype...
18756 var ds = config.dataSource;
18757 this.toolbarItems = [];
18758 if (config.items) {
18759 this.toolbarItems = config.items;
18760 // config.items = [];
18763 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18770 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18774 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18776 * @cfg {Roo.data.Store} dataSource
18777 * The underlying data store providing the paged data
18780 * @cfg {String/HTMLElement/Element} container
18781 * container The id or element that will contain the toolbar
18784 * @cfg {Boolean} displayInfo
18785 * True to display the displayMsg (defaults to false)
18788 * @cfg {Number} pageSize
18789 * The number of records to display per page (defaults to 20)
18793 * @cfg {String} displayMsg
18794 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18796 displayMsg : 'Displaying {0} - {1} of {2}',
18798 * @cfg {String} emptyMsg
18799 * The message to display when no records are found (defaults to "No data to display")
18801 emptyMsg : 'No data to display',
18803 * Customizable piece of the default paging text (defaults to "Page")
18806 beforePageText : "Page",
18808 * Customizable piece of the default paging text (defaults to "of %0")
18811 afterPageText : "of {0}",
18813 * Customizable piece of the default paging text (defaults to "First Page")
18816 firstText : "First Page",
18818 * Customizable piece of the default paging text (defaults to "Previous Page")
18821 prevText : "Previous Page",
18823 * Customizable piece of the default paging text (defaults to "Next Page")
18826 nextText : "Next Page",
18828 * Customizable piece of the default paging text (defaults to "Last Page")
18831 lastText : "Last Page",
18833 * Customizable piece of the default paging text (defaults to "Refresh")
18836 refreshText : "Refresh",
18840 onRender : function(ct, position)
18842 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18843 this.navgroup.parentId = this.id;
18844 this.navgroup.onRender(this.el, null);
18845 // add the buttons to the navgroup
18847 if(this.displayInfo){
18848 Roo.log(this.el.select('ul.navbar-nav',true).first());
18849 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18850 this.displayEl = this.el.select('.x-paging-info', true).first();
18851 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18852 // this.displayEl = navel.el.select('span',true).first();
18858 Roo.each(_this.buttons, function(e){
18859 Roo.factory(e).onRender(_this.el, null);
18863 Roo.each(_this.toolbarItems, function(e) {
18864 _this.navgroup.addItem(e);
18867 this.first = this.navgroup.addItem({
18868 tooltip: this.firstText,
18870 icon : 'fa fa-backward',
18872 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18875 this.prev = this.navgroup.addItem({
18876 tooltip: this.prevText,
18878 icon : 'fa fa-step-backward',
18880 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18882 //this.addSeparator();
18885 var field = this.navgroup.addItem( {
18887 cls : 'x-paging-position',
18889 html : this.beforePageText +
18890 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18891 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18894 this.field = field.el.select('input', true).first();
18895 this.field.on("keydown", this.onPagingKeydown, this);
18896 this.field.on("focus", function(){this.dom.select();});
18899 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18900 //this.field.setHeight(18);
18901 //this.addSeparator();
18902 this.next = this.navgroup.addItem({
18903 tooltip: this.nextText,
18905 html : ' <i class="fa fa-step-forward">',
18907 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18909 this.last = this.navgroup.addItem({
18910 tooltip: this.lastText,
18911 icon : 'fa fa-forward',
18914 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18916 //this.addSeparator();
18917 this.loading = this.navgroup.addItem({
18918 tooltip: this.refreshText,
18919 icon: 'fa fa-refresh',
18921 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18927 updateInfo : function(){
18928 if(this.displayEl){
18929 var count = this.ds.getCount();
18930 var msg = count == 0 ?
18934 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18936 this.displayEl.update(msg);
18941 onLoad : function(ds, r, o){
18942 this.cursor = o.params ? o.params.start : 0;
18943 var d = this.getPageData(),
18947 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18948 this.field.dom.value = ap;
18949 this.first.setDisabled(ap == 1);
18950 this.prev.setDisabled(ap == 1);
18951 this.next.setDisabled(ap == ps);
18952 this.last.setDisabled(ap == ps);
18953 this.loading.enable();
18958 getPageData : function(){
18959 var total = this.ds.getTotalCount();
18962 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18963 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18968 onLoadError : function(){
18969 this.loading.enable();
18973 onPagingKeydown : function(e){
18974 var k = e.getKey();
18975 var d = this.getPageData();
18977 var v = this.field.dom.value, pageNum;
18978 if(!v || isNaN(pageNum = parseInt(v, 10))){
18979 this.field.dom.value = d.activePage;
18982 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18983 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18986 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))
18988 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18989 this.field.dom.value = pageNum;
18990 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18993 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18995 var v = this.field.dom.value, pageNum;
18996 var increment = (e.shiftKey) ? 10 : 1;
18997 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18999 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19000 this.field.dom.value = d.activePage;
19003 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19005 this.field.dom.value = parseInt(v, 10) + increment;
19006 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19007 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19014 beforeLoad : function(){
19016 this.loading.disable();
19021 onClick : function(which){
19028 ds.load({params:{start: 0, limit: this.pageSize}});
19031 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19034 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19037 var total = ds.getTotalCount();
19038 var extra = total % this.pageSize;
19039 var lastStart = extra ? (total - extra) : total-this.pageSize;
19040 ds.load({params:{start: lastStart, limit: this.pageSize}});
19043 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19049 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19050 * @param {Roo.data.Store} store The data store to unbind
19052 unbind : function(ds){
19053 ds.un("beforeload", this.beforeLoad, this);
19054 ds.un("load", this.onLoad, this);
19055 ds.un("loadexception", this.onLoadError, this);
19056 ds.un("remove", this.updateInfo, this);
19057 ds.un("add", this.updateInfo, this);
19058 this.ds = undefined;
19062 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19063 * @param {Roo.data.Store} store The data store to bind
19065 bind : function(ds){
19066 ds.on("beforeload", this.beforeLoad, this);
19067 ds.on("load", this.onLoad, this);
19068 ds.on("loadexception", this.onLoadError, this);
19069 ds.on("remove", this.updateInfo, this);
19070 ds.on("add", this.updateInfo, this);
19081 * @class Roo.bootstrap.MessageBar
19082 * @extends Roo.bootstrap.Component
19083 * Bootstrap MessageBar class
19084 * @cfg {String} html contents of the MessageBar
19085 * @cfg {String} weight (info | success | warning | danger) default info
19086 * @cfg {String} beforeClass insert the bar before the given class
19087 * @cfg {Boolean} closable (true | false) default false
19088 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19091 * Create a new Element
19092 * @param {Object} config The config object
19095 Roo.bootstrap.MessageBar = function(config){
19096 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19099 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19105 beforeClass: 'bootstrap-sticky-wrap',
19107 getAutoCreate : function(){
19111 cls: 'alert alert-dismissable alert-' + this.weight,
19116 html: this.html || ''
19122 cfg.cls += ' alert-messages-fixed';
19136 onRender : function(ct, position)
19138 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19141 var cfg = Roo.apply({}, this.getAutoCreate());
19145 cfg.cls += ' ' + this.cls;
19148 cfg.style = this.style;
19150 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19152 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19155 this.el.select('>button.close').on('click', this.hide, this);
19161 if (!this.rendered) {
19167 this.fireEvent('show', this);
19173 if (!this.rendered) {
19179 this.fireEvent('hide', this);
19182 update : function()
19184 // var e = this.el.dom.firstChild;
19186 // if(this.closable){
19187 // e = e.nextSibling;
19190 // e.data = this.html || '';
19192 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19208 * @class Roo.bootstrap.Graph
19209 * @extends Roo.bootstrap.Component
19210 * Bootstrap Graph class
19214 @cfg {String} graphtype bar | vbar | pie
19215 @cfg {number} g_x coodinator | centre x (pie)
19216 @cfg {number} g_y coodinator | centre y (pie)
19217 @cfg {number} g_r radius (pie)
19218 @cfg {number} g_height height of the chart (respected by all elements in the set)
19219 @cfg {number} g_width width of the chart (respected by all elements in the set)
19220 @cfg {Object} title The title of the chart
19223 -opts (object) options for the chart
19225 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19226 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19228 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.
19229 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19231 o stretch (boolean)
19233 -opts (object) options for the pie
19236 o startAngle (number)
19237 o endAngle (number)
19241 * Create a new Input
19242 * @param {Object} config The config object
19245 Roo.bootstrap.Graph = function(config){
19246 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19252 * The img click event for the img.
19253 * @param {Roo.EventObject} e
19259 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19270 //g_colors: this.colors,
19277 getAutoCreate : function(){
19288 onRender : function(ct,position){
19289 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19290 this.raphael = Raphael(this.el.dom);
19292 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19293 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19294 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19295 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19297 r.text(160, 10, "Single Series Chart").attr(txtattr);
19298 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19299 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19300 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19302 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19303 r.barchart(330, 10, 300, 220, data1);
19304 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19305 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19308 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19309 // r.barchart(30, 30, 560, 250, xdata, {
19310 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19311 // axis : "0 0 1 1",
19312 // axisxlabels : xdata
19313 // //yvalues : cols,
19316 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19318 // this.load(null,xdata,{
19319 // axis : "0 0 1 1",
19320 // axisxlabels : xdata
19325 load : function(graphtype,xdata,opts){
19326 this.raphael.clear();
19328 graphtype = this.graphtype;
19333 var r = this.raphael,
19334 fin = function () {
19335 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19337 fout = function () {
19338 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19340 pfin = function() {
19341 this.sector.stop();
19342 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19345 this.label[0].stop();
19346 this.label[0].attr({ r: 7.5 });
19347 this.label[1].attr({ "font-weight": 800 });
19350 pfout = function() {
19351 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19354 this.label[0].animate({ r: 5 }, 500, "bounce");
19355 this.label[1].attr({ "font-weight": 400 });
19361 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19364 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19367 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19368 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19370 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19377 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19382 setTitle: function(o)
19387 initEvents: function() {
19390 this.el.on('click', this.onClick, this);
19394 onClick : function(e)
19396 Roo.log('img onclick');
19397 this.fireEvent('click', this, e);
19409 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19412 * @class Roo.bootstrap.dash.NumberBox
19413 * @extends Roo.bootstrap.Component
19414 * Bootstrap NumberBox class
19415 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19416 * @cfg {String} headline Box headline
19417 * @cfg {String} content Box content
19418 * @cfg {String} icon Box icon
19419 * @cfg {String} footer Footer text
19420 * @cfg {String} fhref Footer href
19423 * Create a new NumberBox
19424 * @param {Object} config The config object
19428 Roo.bootstrap.dash.NumberBox = function(config){
19429 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19433 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19443 getAutoCreate : function(){
19447 cls : 'small-box bg-' + this.bgcolor,
19455 cls : 'roo-headline',
19456 html : this.headline
19460 cls : 'roo-content',
19461 html : this.content
19475 cls : 'ion ' + this.icon
19484 cls : 'small-box-footer',
19485 href : this.fhref || '#',
19489 cfg.cn.push(footer);
19496 onRender : function(ct,position){
19497 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19504 setHeadline: function (value)
19506 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19509 setFooter: function (value, href)
19511 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19514 this.el.select('a.small-box-footer',true).first().attr('href', href);
19519 setContent: function (value)
19521 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19524 initEvents: function()
19538 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19541 * @class Roo.bootstrap.dash.TabBox
19542 * @extends Roo.bootstrap.Component
19543 * Bootstrap TabBox class
19544 * @cfg {String} title Title of the TabBox
19545 * @cfg {String} icon Icon of the TabBox
19546 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19549 * Create a new TabBox
19550 * @param {Object} config The config object
19554 Roo.bootstrap.dash.TabBox = function(config){
19555 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19560 * When a pane is added
19561 * @param {Roo.bootstrap.dash.TabPane} pane
19568 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19574 getChildContainer : function()
19576 return this.el.select('.tab-content', true).first();
19579 getAutoCreate : function(){
19583 cls: 'pull-left header',
19591 cls: 'fa ' + this.icon
19598 cls: 'nav-tabs-custom',
19602 cls: 'nav nav-tabs pull-right',
19609 cls: 'tab-content no-padding',
19617 initEvents : function()
19619 //Roo.log('add add pane handler');
19620 this.on('addpane', this.onAddPane, this);
19623 * Updates the box title
19624 * @param {String} html to set the title to.
19626 setTitle : function(value)
19628 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19630 onAddPane : function(pane)
19632 //Roo.log('addpane');
19634 // tabs are rendere left to right..
19635 if(!this.showtabs){
19639 var ctr = this.el.select('.nav-tabs', true).first();
19642 var existing = ctr.select('.nav-tab',true);
19643 var qty = existing.getCount();;
19646 var tab = ctr.createChild({
19648 cls : 'nav-tab' + (qty ? '' : ' active'),
19656 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19659 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19661 pane.el.addClass('active');
19666 onTabClick : function(ev,un,ob,pane)
19668 //Roo.log('tab - prev default');
19669 ev.preventDefault();
19672 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19673 pane.tab.addClass('active');
19674 //Roo.log(pane.title);
19675 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19676 // technically we should have a deactivate event.. but maybe add later.
19677 // and it should not de-activate the selected tab...
19679 pane.el.addClass('active');
19680 pane.fireEvent('activate');
19695 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19697 * @class Roo.bootstrap.TabPane
19698 * @extends Roo.bootstrap.Component
19699 * Bootstrap TabPane class
19700 * @cfg {Boolean} active (false | true) Default false
19701 * @cfg {String} title title of panel
19705 * Create a new TabPane
19706 * @param {Object} config The config object
19709 Roo.bootstrap.dash.TabPane = function(config){
19710 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19714 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19719 // the tabBox that this is attached to.
19722 getAutoCreate : function()
19730 cfg.cls += ' active';
19735 initEvents : function()
19737 //Roo.log('trigger add pane handler');
19738 this.parent().fireEvent('addpane', this)
19742 * Updates the tab title
19743 * @param {String} html to set the title to.
19745 setTitle: function(str)
19751 this.tab.select('a'.true).first().dom.innerHTML = str;
19768 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19771 * @class Roo.bootstrap.menu.Menu
19772 * @extends Roo.bootstrap.Component
19773 * Bootstrap Menu class - container for Menu
19774 * @cfg {String} html Text of the menu
19775 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19776 * @cfg {String} icon Font awesome icon
19777 * @cfg {String} pos Menu align to (top | bottom) default bottom
19781 * Create a new Menu
19782 * @param {Object} config The config object
19786 Roo.bootstrap.menu.Menu = function(config){
19787 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19791 * @event beforeshow
19792 * Fires before this menu is displayed
19793 * @param {Roo.bootstrap.menu.Menu} this
19797 * @event beforehide
19798 * Fires before this menu is hidden
19799 * @param {Roo.bootstrap.menu.Menu} this
19804 * Fires after this menu is displayed
19805 * @param {Roo.bootstrap.menu.Menu} this
19810 * Fires after this menu is hidden
19811 * @param {Roo.bootstrap.menu.Menu} this
19816 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19817 * @param {Roo.bootstrap.menu.Menu} this
19818 * @param {Roo.EventObject} e
19825 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19829 weight : 'default',
19834 getChildContainer : function() {
19835 if(this.isSubMenu){
19839 return this.el.select('ul.dropdown-menu', true).first();
19842 getAutoCreate : function()
19847 cls : 'roo-menu-text',
19855 cls : 'fa ' + this.icon
19866 cls : 'dropdown-button btn btn-' + this.weight,
19871 cls : 'dropdown-toggle btn btn-' + this.weight,
19881 cls : 'dropdown-menu'
19887 if(this.pos == 'top'){
19888 cfg.cls += ' dropup';
19891 if(this.isSubMenu){
19894 cls : 'dropdown-menu'
19901 onRender : function(ct, position)
19903 this.isSubMenu = ct.hasClass('dropdown-submenu');
19905 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19908 initEvents : function()
19910 if(this.isSubMenu){
19914 this.hidden = true;
19916 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19917 this.triggerEl.on('click', this.onTriggerPress, this);
19919 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19920 this.buttonEl.on('click', this.onClick, this);
19926 if(this.isSubMenu){
19930 return this.el.select('ul.dropdown-menu', true).first();
19933 onClick : function(e)
19935 this.fireEvent("click", this, e);
19938 onTriggerPress : function(e)
19940 if (this.isVisible()) {
19947 isVisible : function(){
19948 return !this.hidden;
19953 this.fireEvent("beforeshow", this);
19955 this.hidden = false;
19956 this.el.addClass('open');
19958 Roo.get(document).on("mouseup", this.onMouseUp, this);
19960 this.fireEvent("show", this);
19967 this.fireEvent("beforehide", this);
19969 this.hidden = true;
19970 this.el.removeClass('open');
19972 Roo.get(document).un("mouseup", this.onMouseUp);
19974 this.fireEvent("hide", this);
19977 onMouseUp : function()
19991 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19994 * @class Roo.bootstrap.menu.Item
19995 * @extends Roo.bootstrap.Component
19996 * Bootstrap MenuItem class
19997 * @cfg {Boolean} submenu (true | false) default false
19998 * @cfg {String} html text of the item
19999 * @cfg {String} href the link
20000 * @cfg {Boolean} disable (true | false) default false
20001 * @cfg {Boolean} preventDefault (true | false) default true
20002 * @cfg {String} icon Font awesome icon
20003 * @cfg {String} pos Submenu align to (left | right) default right
20007 * Create a new Item
20008 * @param {Object} config The config object
20012 Roo.bootstrap.menu.Item = function(config){
20013 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20017 * Fires when the mouse is hovering over this menu
20018 * @param {Roo.bootstrap.menu.Item} this
20019 * @param {Roo.EventObject} e
20024 * Fires when the mouse exits this menu
20025 * @param {Roo.bootstrap.menu.Item} this
20026 * @param {Roo.EventObject} e
20032 * The raw click event for the entire grid.
20033 * @param {Roo.EventObject} e
20039 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20044 preventDefault: true,
20049 getAutoCreate : function()
20054 cls : 'roo-menu-item-text',
20062 cls : 'fa ' + this.icon
20071 href : this.href || '#',
20078 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20082 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20084 if(this.pos == 'left'){
20085 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20092 initEvents : function()
20094 this.el.on('mouseover', this.onMouseOver, this);
20095 this.el.on('mouseout', this.onMouseOut, this);
20097 this.el.select('a', true).first().on('click', this.onClick, this);
20101 onClick : function(e)
20103 if(this.preventDefault){
20104 e.preventDefault();
20107 this.fireEvent("click", this, e);
20110 onMouseOver : function(e)
20112 if(this.submenu && this.pos == 'left'){
20113 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20116 this.fireEvent("mouseover", this, e);
20119 onMouseOut : function(e)
20121 this.fireEvent("mouseout", this, e);
20133 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20136 * @class Roo.bootstrap.menu.Separator
20137 * @extends Roo.bootstrap.Component
20138 * Bootstrap Separator class
20141 * Create a new Separator
20142 * @param {Object} config The config object
20146 Roo.bootstrap.menu.Separator = function(config){
20147 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20150 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20152 getAutoCreate : function(){