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';
972 * @class Roo.bootstrap.Img
973 * @extends Roo.bootstrap.Component
974 * Bootstrap Img class
975 * @cfg {Boolean} imgResponsive false | true
976 * @cfg {String} border rounded | circle | thumbnail
977 * @cfg {String} src image source
978 * @cfg {String} alt image alternative text
979 * @cfg {String} href a tag href
980 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
984 * @param {Object} config The config object
987 Roo.bootstrap.Img = function(config){
988 Roo.bootstrap.Img.superclass.constructor.call(this, config);
994 * The img click event for the img.
995 * @param {Roo.EventObject} e
1001 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1003 imgResponsive: true,
1009 getAutoCreate : function(){
1013 cls: (this.imgResponsive) ? 'img-responsive' : '',
1017 cfg.html = this.html || cfg.html;
1019 cfg.src = this.src || cfg.src;
1021 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1022 cfg.cls += ' img-' + this.border;
1039 a.target = this.target;
1045 return (this.href) ? a : cfg;
1048 initEvents: function() {
1051 this.el.on('click', this.onClick, this);
1055 onClick : function(e)
1057 Roo.log('img onclick');
1058 this.fireEvent('click', this, e);
1072 * @class Roo.bootstrap.Link
1073 * @extends Roo.bootstrap.Component
1074 * Bootstrap Link Class
1075 * @cfg {String} alt image alternative text
1076 * @cfg {String} href a tag href
1077 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1078 * @cfg {String} html the content of the link.
1082 * Create a new Input
1083 * @param {Object} config The config object
1086 Roo.bootstrap.Link = function(config){
1087 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1093 * The img click event for the img.
1094 * @param {Roo.EventObject} e
1100 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1105 getAutoCreate : function(){
1109 html : this.html || 'html-missing'
1116 cfg.href = this.href || '#';
1118 cfg.target = this.target;
1124 initEvents: function() {
1127 this.el.on('click', this.onClick, this);
1131 onClick : function(e)
1133 //Roo.log('img onclick');
1134 this.fireEvent('click', this, e);
1147 * @class Roo.bootstrap.Header
1148 * @extends Roo.bootstrap.Component
1149 * Bootstrap Header class
1150 * @cfg {String} html content of header
1151 * @cfg {Number} level (1|2|3|4|5|6) default 1
1154 * Create a new Header
1155 * @param {Object} config The config object
1159 Roo.bootstrap.Header = function(config){
1160 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1163 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1171 getAutoCreate : function(){
1174 tag: 'h' + (1 *this.level),
1175 html: this.html || 'fill in html'
1187 * Ext JS Library 1.1.1
1188 * Copyright(c) 2006-2007, Ext JS, LLC.
1190 * Originally Released Under LGPL - original licence link has changed is not relivant.
1193 * <script type="text/javascript">
1197 * @class Roo.bootstrap.MenuMgr
1198 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1201 Roo.bootstrap.MenuMgr = function(){
1202 var menus, active, groups = {}, attached = false, lastShow = new Date();
1204 // private - called when first menu is created
1207 active = new Roo.util.MixedCollection();
1208 Roo.get(document).addKeyListener(27, function(){
1209 if(active.length > 0){
1217 if(active && active.length > 0){
1218 var c = active.clone();
1228 if(active.length < 1){
1229 Roo.get(document).un("mouseup", onMouseDown);
1237 var last = active.last();
1238 lastShow = new Date();
1241 Roo.get(document).on("mouseup", onMouseDown);
1246 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1247 m.parentMenu.activeChild = m;
1248 }else if(last && last.isVisible()){
1249 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1254 function onBeforeHide(m){
1256 m.activeChild.hide();
1258 if(m.autoHideTimer){
1259 clearTimeout(m.autoHideTimer);
1260 delete m.autoHideTimer;
1265 function onBeforeShow(m){
1266 var pm = m.parentMenu;
1267 if(!pm && !m.allowOtherMenus){
1269 }else if(pm && pm.activeChild && active != m){
1270 pm.activeChild.hide();
1275 function onMouseDown(e){
1276 Roo.log("on MouseDown");
1277 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1285 function onBeforeCheck(mi, state){
1287 var g = groups[mi.group];
1288 for(var i = 0, l = g.length; i < l; i++){
1290 g[i].setChecked(false);
1299 * Hides all menus that are currently visible
1301 hideAll : function(){
1306 register : function(menu){
1310 menus[menu.id] = menu;
1311 menu.on("beforehide", onBeforeHide);
1312 menu.on("hide", onHide);
1313 menu.on("beforeshow", onBeforeShow);
1314 menu.on("show", onShow);
1316 if(g && menu.events["checkchange"]){
1320 groups[g].push(menu);
1321 menu.on("checkchange", onCheck);
1326 * Returns a {@link Roo.menu.Menu} object
1327 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1328 * be used to generate and return a new Menu instance.
1330 get : function(menu){
1331 if(typeof menu == "string"){ // menu id
1333 }else if(menu.events){ // menu instance
1336 /*else if(typeof menu.length == 'number'){ // array of menu items?
1337 return new Roo.bootstrap.Menu({items:menu});
1338 }else{ // otherwise, must be a config
1339 return new Roo.bootstrap.Menu(menu);
1346 unregister : function(menu){
1347 delete menus[menu.id];
1348 menu.un("beforehide", onBeforeHide);
1349 menu.un("hide", onHide);
1350 menu.un("beforeshow", onBeforeShow);
1351 menu.un("show", onShow);
1353 if(g && menu.events["checkchange"]){
1354 groups[g].remove(menu);
1355 menu.un("checkchange", onCheck);
1360 registerCheckable : function(menuItem){
1361 var g = menuItem.group;
1366 groups[g].push(menuItem);
1367 menuItem.on("beforecheckchange", onBeforeCheck);
1372 unregisterCheckable : function(menuItem){
1373 var g = menuItem.group;
1375 groups[g].remove(menuItem);
1376 menuItem.un("beforecheckchange", onBeforeCheck);
1388 * @class Roo.bootstrap.Menu
1389 * @extends Roo.bootstrap.Component
1390 * Bootstrap Menu class - container for MenuItems
1391 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1395 * @param {Object} config The config object
1399 Roo.bootstrap.Menu = function(config){
1400 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1401 if (this.registerMenu) {
1402 Roo.bootstrap.MenuMgr.register(this);
1407 * Fires before this menu is displayed
1408 * @param {Roo.menu.Menu} this
1413 * Fires before this menu is hidden
1414 * @param {Roo.menu.Menu} this
1419 * Fires after this menu is displayed
1420 * @param {Roo.menu.Menu} this
1425 * Fires after this menu is hidden
1426 * @param {Roo.menu.Menu} this
1431 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1432 * @param {Roo.menu.Menu} this
1433 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1434 * @param {Roo.EventObject} e
1439 * Fires when the mouse is hovering over this menu
1440 * @param {Roo.menu.Menu} this
1441 * @param {Roo.EventObject} e
1442 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1447 * Fires when the mouse exits this menu
1448 * @param {Roo.menu.Menu} this
1449 * @param {Roo.EventObject} e
1450 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1455 * Fires when a menu item contained in this menu is clicked
1456 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1457 * @param {Roo.EventObject} e
1461 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1464 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1468 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1471 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1473 registerMenu : true,
1475 menuItems :false, // stores the menu items..
1481 getChildContainer : function() {
1485 getAutoCreate : function(){
1487 //if (['right'].indexOf(this.align)!==-1) {
1488 // cfg.cn[1].cls += ' pull-right'
1494 cls : 'dropdown-menu' ,
1495 style : 'z-index:1000'
1499 if (this.type === 'submenu') {
1500 cfg.cls = 'submenu active';
1502 if (this.type === 'treeview') {
1503 cfg.cls = 'treeview-menu';
1508 initEvents : function() {
1510 // Roo.log("ADD event");
1511 // Roo.log(this.triggerEl.dom);
1512 this.triggerEl.on('click', this.onTriggerPress, this);
1513 this.triggerEl.addClass('dropdown-toggle');
1514 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1516 this.el.on("mouseover", this.onMouseOver, this);
1517 this.el.on("mouseout", this.onMouseOut, this);
1521 findTargetItem : function(e){
1522 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1526 //Roo.log(t); Roo.log(t.id);
1528 //Roo.log(this.menuitems);
1529 return this.menuitems.get(t.id);
1531 //return this.items.get(t.menuItemId);
1536 onClick : function(e){
1537 Roo.log("menu.onClick");
1538 var t = this.findTargetItem(e);
1544 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1545 if(t == this.activeItem && t.shouldDeactivate(e)){
1546 this.activeItem.deactivate();
1547 delete this.activeItem;
1551 this.setActiveItem(t, true);
1558 Roo.log('pass click event');
1562 this.fireEvent("click", this, t, e);
1566 onMouseOver : function(e){
1567 var t = this.findTargetItem(e);
1570 // if(t.canActivate && !t.disabled){
1571 // this.setActiveItem(t, true);
1575 this.fireEvent("mouseover", this, e, t);
1577 isVisible : function(){
1578 return !this.hidden;
1580 onMouseOut : function(e){
1581 var t = this.findTargetItem(e);
1584 // if(t == this.activeItem && t.shouldDeactivate(e)){
1585 // this.activeItem.deactivate();
1586 // delete this.activeItem;
1589 this.fireEvent("mouseout", this, e, t);
1594 * Displays this menu relative to another element
1595 * @param {String/HTMLElement/Roo.Element} element The element to align to
1596 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1597 * the element (defaults to this.defaultAlign)
1598 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1600 show : function(el, pos, parentMenu){
1601 this.parentMenu = parentMenu;
1605 this.fireEvent("beforeshow", this);
1606 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1609 * Displays this menu at a specific xy position
1610 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1611 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1613 showAt : function(xy, parentMenu, /* private: */_e){
1614 this.parentMenu = parentMenu;
1619 this.fireEvent("beforeshow", this);
1621 //xy = this.el.adjustForConstraints(xy);
1623 //this.el.setXY(xy);
1625 this.hideMenuItems();
1626 this.hidden = false;
1627 this.triggerEl.addClass('open');
1629 this.fireEvent("show", this);
1635 this.doFocus.defer(50, this);
1639 doFocus : function(){
1641 this.focusEl.focus();
1646 * Hides this menu and optionally all parent menus
1647 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1649 hide : function(deep){
1651 this.hideMenuItems();
1652 if(this.el && this.isVisible()){
1653 this.fireEvent("beforehide", this);
1654 if(this.activeItem){
1655 this.activeItem.deactivate();
1656 this.activeItem = null;
1658 this.triggerEl.removeClass('open');;
1660 this.fireEvent("hide", this);
1662 if(deep === true && this.parentMenu){
1663 this.parentMenu.hide(true);
1667 onTriggerPress : function(e)
1670 Roo.log('trigger press');
1671 //Roo.log(e.getTarget());
1672 // Roo.log(this.triggerEl.dom);
1673 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1676 if (this.isVisible()) {
1680 this.show(this.triggerEl, false, false);
1689 hideMenuItems : function()
1691 //$(backdrop).remove()
1692 Roo.select('.open',true).each(function(aa) {
1694 aa.removeClass('open');
1695 //var parent = getParent($(this))
1696 //var relatedTarget = { relatedTarget: this }
1698 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1699 //if (e.isDefaultPrevented()) return
1700 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1703 addxtypeChild : function (tree, cntr) {
1704 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1706 this.menuitems.add(comp);
1727 * @class Roo.bootstrap.MenuItem
1728 * @extends Roo.bootstrap.Component
1729 * Bootstrap MenuItem class
1730 * @cfg {String} html the menu label
1731 * @cfg {String} href the link
1732 * @cfg {Boolean} preventDefault (true | false) default true
1736 * Create a new MenuItem
1737 * @param {Object} config The config object
1741 Roo.bootstrap.MenuItem = function(config){
1742 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1747 * The raw click event for the entire grid.
1748 * @param {Roo.EventObject} e
1754 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1758 preventDefault: true,
1760 getAutoCreate : function(){
1763 cls: 'dropdown-menu-item',
1772 if (this.parent().type == 'treeview') {
1773 cfg.cls = 'treeview-menu';
1776 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1777 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1781 initEvents: function() {
1783 //this.el.select('a').on('click', this.onClick, this);
1786 onClick : function(e)
1788 Roo.log('item on click ');
1789 //if(this.preventDefault){
1790 // e.preventDefault();
1792 //this.parent().hideMenuItems();
1794 this.fireEvent('click', this, e);
1813 * @class Roo.bootstrap.MenuSeparator
1814 * @extends Roo.bootstrap.Component
1815 * Bootstrap MenuSeparator class
1818 * Create a new MenuItem
1819 * @param {Object} config The config object
1823 Roo.bootstrap.MenuSeparator = function(config){
1824 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1827 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1829 getAutoCreate : function(){
1844 <div class="modal fade">
1845 <div class="modal-dialog">
1846 <div class="modal-content">
1847 <div class="modal-header">
1848 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1849 <h4 class="modal-title">Modal title</h4>
1851 <div class="modal-body">
1852 <p>One fine body…</p>
1854 <div class="modal-footer">
1855 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1856 <button type="button" class="btn btn-primary">Save changes</button>
1858 </div><!-- /.modal-content -->
1859 </div><!-- /.modal-dialog -->
1860 </div><!-- /.modal -->
1870 * @class Roo.bootstrap.Modal
1871 * @extends Roo.bootstrap.Component
1872 * Bootstrap Modal class
1873 * @cfg {String} title Title of dialog
1874 * @cfg {Boolean} specificTitle (true|false) default false
1875 * @cfg {Array} buttons Array of buttons or standard button set..
1876 * @cfg {String} buttonPosition (left|right|center) default right
1879 * Create a new Modal Dialog
1880 * @param {Object} config The config object
1883 Roo.bootstrap.Modal = function(config){
1884 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1889 * The raw btnclick event for the button
1890 * @param {Roo.EventObject} e
1894 this.buttons = this.buttons || [];
1897 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1899 title : 'test dialog',
1906 specificTitle: false,
1908 buttonPosition: 'right',
1910 onRender : function(ct, position)
1912 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1915 var cfg = Roo.apply({}, this.getAutoCreate());
1918 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1920 //if (!cfg.name.length) {
1924 cfg.cls += ' ' + this.cls;
1927 cfg.style = this.style;
1929 this.el = Roo.get(document.body).createChild(cfg, position);
1931 //var type = this.el.dom.type;
1933 if(this.tabIndex !== undefined){
1934 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1939 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1940 this.maskEl.enableDisplayMode("block");
1942 //this.el.addClass("x-dlg-modal");
1944 if (this.buttons.length) {
1945 Roo.each(this.buttons, function(bb) {
1946 b = Roo.apply({}, bb);
1947 b.xns = b.xns || Roo.bootstrap;
1948 b.xtype = b.xtype || 'Button';
1949 if (typeof(b.listeners) == 'undefined') {
1950 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1953 var btn = Roo.factory(b);
1955 btn.onRender(this.el.select('.modal-footer div').first());
1959 // render the children.
1962 if(typeof(this.items) != 'undefined'){
1963 var items = this.items;
1966 for(var i =0;i < items.length;i++) {
1967 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1971 this.items = nitems;
1973 this.body = this.el.select('.modal-body',true).first();
1974 this.close = this.el.select('.modal-header .close', true).first();
1975 this.footer = this.el.select('.modal-footer',true).first();
1977 //this.el.addClass([this.fieldClass, this.cls]);
1980 getAutoCreate : function(){
1985 html : this.html || ''
1990 cls : 'modal-title',
1994 if(this.specificTitle){
2000 style : 'display: none',
2003 cls: "modal-dialog",
2006 cls : "modal-content",
2009 cls : 'modal-header',
2021 cls : 'modal-footer',
2025 cls: 'btn-' + this.buttonPosition
2044 getChildContainer : function() {
2046 return this.el.select('.modal-body',true).first();
2049 getButtonContainer : function() {
2050 return this.el.select('.modal-footer div',true).first();
2053 initEvents : function()
2055 this.el.select('.modal-header .close').on('click', this.hide, this);
2057 // this.addxtype(this);
2061 if (!this.rendered) {
2065 this.el.addClass('on');
2066 this.el.removeClass('fade');
2067 this.el.setStyle('display', 'block');
2068 Roo.get(document.body).addClass("x-body-masked");
2069 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2071 this.el.setStyle('zIndex', '10001');
2072 this.fireEvent('show', this);
2078 Roo.log('Modal hide?!');
2080 Roo.get(document.body).removeClass("x-body-masked");
2081 this.el.removeClass('on');
2082 this.el.addClass('fade');
2083 this.el.setStyle('display', 'none');
2084 this.fireEvent('hide', this);
2087 addButton : function(str, cb)
2091 var b = Roo.apply({}, { html : str } );
2092 b.xns = b.xns || Roo.bootstrap;
2093 b.xtype = b.xtype || 'Button';
2094 if (typeof(b.listeners) == 'undefined') {
2095 b.listeners = { click : cb.createDelegate(this) };
2098 var btn = Roo.factory(b);
2100 btn.onRender(this.el.select('.modal-footer div').first());
2106 setDefaultButton : function(btn)
2108 //this.el.select('.modal-footer').()
2110 resizeTo: function(w,h)
2114 setContentSize : function(w, h)
2118 onButtonClick: function(btn,e)
2121 this.fireEvent('btnclick', btn.name, e);
2123 setTitle: function(str) {
2124 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2130 Roo.apply(Roo.bootstrap.Modal, {
2132 * Button config that displays a single OK button
2141 * Button config that displays Yes and No buttons
2157 * Button config that displays OK and Cancel buttons
2172 * Button config that displays Yes, No and Cancel buttons
2194 * messagebox - can be used as a replace
2198 * @class Roo.MessageBox
2199 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2203 Roo.Msg.alert('Status', 'Changes saved successfully.');
2205 // Prompt for user data:
2206 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2208 // process text value...
2212 // Show a dialog using config options:
2214 title:'Save Changes?',
2215 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2216 buttons: Roo.Msg.YESNOCANCEL,
2223 Roo.bootstrap.MessageBox = function(){
2224 var dlg, opt, mask, waitTimer;
2225 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2226 var buttons, activeTextEl, bwidth;
2230 var handleButton = function(button){
2232 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2236 var handleHide = function(){
2238 dlg.el.removeClass(opt.cls);
2241 // Roo.TaskMgr.stop(waitTimer);
2242 // waitTimer = null;
2247 var updateButtons = function(b){
2250 buttons["ok"].hide();
2251 buttons["cancel"].hide();
2252 buttons["yes"].hide();
2253 buttons["no"].hide();
2254 //dlg.footer.dom.style.display = 'none';
2257 dlg.footer.dom.style.display = '';
2258 for(var k in buttons){
2259 if(typeof buttons[k] != "function"){
2262 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2263 width += buttons[k].el.getWidth()+15;
2273 var handleEsc = function(d, k, e){
2274 if(opt && opt.closable !== false){
2284 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2285 * @return {Roo.BasicDialog} The BasicDialog element
2287 getDialog : function(){
2289 dlg = new Roo.bootstrap.Modal( {
2292 //constraintoviewport:false,
2294 //collapsible : false,
2299 //buttonAlign:"center",
2300 closeClick : function(){
2301 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2304 handleButton("cancel");
2309 dlg.on("hide", handleHide);
2311 //dlg.addKeyListener(27, handleEsc);
2313 this.buttons = buttons;
2314 var bt = this.buttonText;
2315 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2316 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2317 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2318 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2320 bodyEl = dlg.body.createChild({
2322 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2323 '<textarea class="roo-mb-textarea"></textarea>' +
2324 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2326 msgEl = bodyEl.dom.firstChild;
2327 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2328 textboxEl.enableDisplayMode();
2329 textboxEl.addKeyListener([10,13], function(){
2330 if(dlg.isVisible() && opt && opt.buttons){
2333 }else if(opt.buttons.yes){
2334 handleButton("yes");
2338 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2339 textareaEl.enableDisplayMode();
2340 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2341 progressEl.enableDisplayMode();
2342 var pf = progressEl.dom.firstChild;
2344 pp = Roo.get(pf.firstChild);
2345 pp.setHeight(pf.offsetHeight);
2353 * Updates the message box body text
2354 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2355 * the XHTML-compliant non-breaking space character '&#160;')
2356 * @return {Roo.MessageBox} This message box
2358 updateText : function(text){
2359 if(!dlg.isVisible() && !opt.width){
2360 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2362 msgEl.innerHTML = text || ' ';
2364 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2365 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2367 Math.min(opt.width || cw , this.maxWidth),
2368 Math.max(opt.minWidth || this.minWidth, bwidth)
2371 activeTextEl.setWidth(w);
2373 if(dlg.isVisible()){
2374 dlg.fixedcenter = false;
2376 // to big, make it scroll. = But as usual stupid IE does not support
2379 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2380 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2381 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2383 bodyEl.dom.style.height = '';
2384 bodyEl.dom.style.overflowY = '';
2387 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2389 bodyEl.dom.style.overflowX = '';
2392 dlg.setContentSize(w, bodyEl.getHeight());
2393 if(dlg.isVisible()){
2394 dlg.fixedcenter = true;
2400 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2401 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2402 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2403 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2404 * @return {Roo.MessageBox} This message box
2406 updateProgress : function(value, text){
2408 this.updateText(text);
2410 if (pp) { // weird bug on my firefox - for some reason this is not defined
2411 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2417 * Returns true if the message box is currently displayed
2418 * @return {Boolean} True if the message box is visible, else false
2420 isVisible : function(){
2421 return dlg && dlg.isVisible();
2425 * Hides the message box if it is displayed
2428 if(this.isVisible()){
2434 * Displays a new message box, or reinitializes an existing message box, based on the config options
2435 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2436 * The following config object properties are supported:
2438 Property Type Description
2439 ---------- --------------- ------------------------------------------------------------------------------------
2440 animEl String/Element An id or Element from which the message box should animate as it opens and
2441 closes (defaults to undefined)
2442 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2443 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2444 closable Boolean False to hide the top-right close button (defaults to true). Note that
2445 progress and wait dialogs will ignore this property and always hide the
2446 close button as they can only be closed programmatically.
2447 cls String A custom CSS class to apply to the message box element
2448 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2449 displayed (defaults to 75)
2450 fn Function A callback function to execute after closing the dialog. The arguments to the
2451 function will be btn (the name of the button that was clicked, if applicable,
2452 e.g. "ok"), and text (the value of the active text field, if applicable).
2453 Progress and wait dialogs will ignore this option since they do not respond to
2454 user actions and can only be closed programmatically, so any required function
2455 should be called by the same code after it closes the dialog.
2456 icon String A CSS class that provides a background image to be used as an icon for
2457 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2458 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2459 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2460 modal Boolean False to allow user interaction with the page while the message box is
2461 displayed (defaults to true)
2462 msg String A string that will replace the existing message box body text (defaults
2463 to the XHTML-compliant non-breaking space character ' ')
2464 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2465 progress Boolean True to display a progress bar (defaults to false)
2466 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2467 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2468 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2469 title String The title text
2470 value String The string value to set into the active textbox element if displayed
2471 wait Boolean True to display a progress bar (defaults to false)
2472 width Number The width of the dialog in pixels
2479 msg: 'Please enter your address:',
2481 buttons: Roo.MessageBox.OKCANCEL,
2484 animEl: 'addAddressBtn'
2487 * @param {Object} config Configuration options
2488 * @return {Roo.MessageBox} This message box
2490 show : function(options)
2493 // this causes nightmares if you show one dialog after another
2494 // especially on callbacks..
2496 if(this.isVisible()){
2499 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2500 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2501 Roo.log("New Dialog Message:" + options.msg )
2502 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2503 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2506 var d = this.getDialog();
2508 d.setTitle(opt.title || " ");
2509 d.close.setDisplayed(opt.closable !== false);
2510 activeTextEl = textboxEl;
2511 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2516 textareaEl.setHeight(typeof opt.multiline == "number" ?
2517 opt.multiline : this.defaultTextHeight);
2518 activeTextEl = textareaEl;
2527 progressEl.setDisplayed(opt.progress === true);
2528 this.updateProgress(0);
2529 activeTextEl.dom.value = opt.value || "";
2531 dlg.setDefaultButton(activeTextEl);
2533 var bs = opt.buttons;
2537 }else if(bs && bs.yes){
2538 db = buttons["yes"];
2540 dlg.setDefaultButton(db);
2542 bwidth = updateButtons(opt.buttons);
2543 this.updateText(opt.msg);
2545 d.el.addClass(opt.cls);
2547 d.proxyDrag = opt.proxyDrag === true;
2548 d.modal = opt.modal !== false;
2549 d.mask = opt.modal !== false ? mask : false;
2551 // force it to the end of the z-index stack so it gets a cursor in FF
2552 document.body.appendChild(dlg.el.dom);
2553 d.animateTarget = null;
2554 d.show(options.animEl);
2560 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2561 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2562 * and closing the message box when the process is complete.
2563 * @param {String} title The title bar text
2564 * @param {String} msg The message box body text
2565 * @return {Roo.MessageBox} This message box
2567 progress : function(title, msg){
2574 minWidth: this.minProgressWidth,
2581 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2582 * If a callback function is passed it will be called after the user clicks the button, and the
2583 * id of the button that was clicked will be passed as the only parameter to the callback
2584 * (could also be the top-right close button).
2585 * @param {String} title The title bar text
2586 * @param {String} msg The message box body text
2587 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2588 * @param {Object} scope (optional) The scope of the callback function
2589 * @return {Roo.MessageBox} This message box
2591 alert : function(title, msg, fn, scope){
2604 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2605 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2606 * You are responsible for closing the message box when the process is complete.
2607 * @param {String} msg The message box body text
2608 * @param {String} title (optional) The title bar text
2609 * @return {Roo.MessageBox} This message box
2611 wait : function(msg, title){
2622 waitTimer = Roo.TaskMgr.start({
2624 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2632 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2633 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2634 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2635 * @param {String} title The title bar text
2636 * @param {String} msg The message box body text
2637 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2638 * @param {Object} scope (optional) The scope of the callback function
2639 * @return {Roo.MessageBox} This message box
2641 confirm : function(title, msg, fn, scope){
2645 buttons: this.YESNO,
2654 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2655 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2656 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2657 * (could also be the top-right close button) and the text that was entered will be passed as the two
2658 * parameters to the callback.
2659 * @param {String} title The title bar text
2660 * @param {String} msg The message box body text
2661 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2662 * @param {Object} scope (optional) The scope of the callback function
2663 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2664 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2665 * @return {Roo.MessageBox} This message box
2667 prompt : function(title, msg, fn, scope, multiline){
2671 buttons: this.OKCANCEL,
2676 multiline: multiline,
2683 * Button config that displays a single OK button
2688 * Button config that displays Yes and No buttons
2691 YESNO : {yes:true, no:true},
2693 * Button config that displays OK and Cancel buttons
2696 OKCANCEL : {ok:true, cancel:true},
2698 * Button config that displays Yes, No and Cancel buttons
2701 YESNOCANCEL : {yes:true, no:true, cancel:true},
2704 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2707 defaultTextHeight : 75,
2709 * The maximum width in pixels of the message box (defaults to 600)
2714 * The minimum width in pixels of the message box (defaults to 100)
2719 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2720 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2723 minProgressWidth : 250,
2725 * An object containing the default button text strings that can be overriden for localized language support.
2726 * Supported properties are: ok, cancel, yes and no.
2727 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2740 * Shorthand for {@link Roo.MessageBox}
2742 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2743 Roo.Msg = Roo.Msg || Roo.MessageBox;
2752 * @class Roo.bootstrap.Navbar
2753 * @extends Roo.bootstrap.Component
2754 * Bootstrap Navbar class
2757 * Create a new Navbar
2758 * @param {Object} config The config object
2762 Roo.bootstrap.Navbar = function(config){
2763 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2767 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2776 getAutoCreate : function(){
2779 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2783 initEvents :function ()
2785 //Roo.log(this.el.select('.navbar-toggle',true));
2786 this.el.select('.navbar-toggle',true).on('click', function() {
2787 // Roo.log('click');
2788 this.el.select('.navbar-collapse',true).toggleClass('in');
2796 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2798 var size = this.el.getSize();
2799 this.maskEl.setSize(size.width, size.height);
2800 this.maskEl.enableDisplayMode("block");
2809 getChildContainer : function()
2811 if (this.el.select('.collapse').getCount()) {
2812 return this.el.select('.collapse',true).first();
2845 * @class Roo.bootstrap.NavSimplebar
2846 * @extends Roo.bootstrap.Navbar
2847 * Bootstrap Sidebar class
2849 * @cfg {Boolean} inverse is inverted color
2851 * @cfg {String} type (nav | pills | tabs)
2852 * @cfg {Boolean} arrangement stacked | justified
2853 * @cfg {String} align (left | right) alignment
2855 * @cfg {Boolean} main (true|false) main nav bar? default false
2856 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2858 * @cfg {String} tag (header|footer|nav|div) default is nav
2864 * Create a new Sidebar
2865 * @param {Object} config The config object
2869 Roo.bootstrap.NavSimplebar = function(config){
2870 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2873 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2889 getAutoCreate : function(){
2893 tag : this.tag || 'div',
2906 this.type = this.type || 'nav';
2907 if (['tabs','pills'].indexOf(this.type)!==-1) {
2908 cfg.cn[0].cls += ' nav-' + this.type
2912 if (this.type!=='nav') {
2913 Roo.log('nav type must be nav/tabs/pills')
2915 cfg.cn[0].cls += ' navbar-nav'
2921 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2922 cfg.cn[0].cls += ' nav-' + this.arrangement;
2926 if (this.align === 'right') {
2927 cfg.cn[0].cls += ' navbar-right';
2931 cfg.cls += ' navbar-inverse';
2958 * @class Roo.bootstrap.NavHeaderbar
2959 * @extends Roo.bootstrap.NavSimplebar
2960 * Bootstrap Sidebar class
2962 * @cfg {String} brand what is brand
2963 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2964 * @cfg {String} brand_href href of the brand
2967 * Create a new Sidebar
2968 * @param {Object} config The config object
2972 Roo.bootstrap.NavHeaderbar = function(config){
2973 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
2976 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
2983 getAutoCreate : function(){
2988 tag: this.nav || 'nav',
2994 cls: 'navbar-header',
2999 cls: 'navbar-toggle',
3000 'data-toggle': 'collapse',
3005 html: 'Toggle navigation'
3025 cls: 'collapse navbar-collapse'
3030 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3032 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3033 cfg.cls += ' navbar-' + this.position;
3035 // tag can override this..
3037 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3040 if (this.brand !== '') {
3043 href: this.brand_href ? this.brand_href : '#',
3044 cls: 'navbar-brand',
3052 cfg.cls += ' main-nav';
3077 * @class Roo.bootstrap.NavSidebar
3078 * @extends Roo.bootstrap.Navbar
3079 * Bootstrap Sidebar class
3082 * Create a new Sidebar
3083 * @param {Object} config The config object
3087 Roo.bootstrap.NavSidebar = function(config){
3088 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3091 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3093 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3095 getAutoCreate : function(){
3100 cls: 'sidebar sidebar-nav'
3122 * @class Roo.bootstrap.NavGroup
3123 * @extends Roo.bootstrap.Component
3124 * Bootstrap NavGroup class
3125 * @cfg {String} align left | right
3126 * @cfg {Boolean} inverse false | true
3127 * @cfg {String} type (nav|pills|tab) default nav
3128 * @cfg {String} navId - reference Id for navbar.
3132 * Create a new nav group
3133 * @param {Object} config The config object
3136 Roo.bootstrap.NavGroup = function(config){
3137 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3139 Roo.bootstrap.NavGroup.register(this);
3143 * Fires when the active item changes
3144 * @param {Roo.bootstrap.NavGroup} this
3145 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3146 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3153 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3164 getAutoCreate : function()
3166 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3173 if (['tabs','pills'].indexOf(this.type)!==-1) {
3174 cfg.cls += ' nav-' + this.type
3176 if (this.type!=='nav') {
3177 Roo.log('nav type must be nav/tabs/pills')
3179 cfg.cls += ' navbar-nav'
3182 if (this.parent().sidebar) {
3185 cls: 'dashboard-menu sidebar-menu'
3191 if (this.form === true) {
3197 if (this.align === 'right') {
3198 cfg.cls += ' navbar-right';
3200 cfg.cls += ' navbar-left';
3204 if (this.align === 'right') {
3205 cfg.cls += ' navbar-right';
3209 cfg.cls += ' navbar-inverse';
3217 setActiveItem : function(item)
3220 Roo.each(this.navItems, function(v){
3225 v.setActive(false, true);
3232 item.setActive(true, true);
3233 this.fireEvent('changed', this, item, prev);
3238 addItem : function(cfg)
3240 var cn = new Roo.bootstrap.NavItem(cfg);
3242 cn.parentId = this.id;
3243 cn.onRender(this.el, null);
3247 register : function(item)
3249 this.navItems.push( item);
3250 item.navId = this.navId;
3253 getNavItem: function(tabId)
3256 Roo.each(this.navItems, function(e) {
3257 if (e.tabId == tabId) {
3273 Roo.apply(Roo.bootstrap.NavGroup, {
3277 register : function(navgrp)
3279 this.groups[navgrp.navId] = navgrp;
3282 get: function(navId) {
3283 return this.groups[navId];
3298 * @class Roo.bootstrap.NavItem
3299 * @extends Roo.bootstrap.Component
3300 * Bootstrap Navbar.NavItem class
3301 * @cfg {String} href link to
3302 * @cfg {String} html content of button
3303 * @cfg {String} badge text inside badge
3304 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3305 * @cfg {String} glyphicon name of glyphicon
3306 * @cfg {String} icon name of font awesome icon
3307 * @cfg {Boolean} active Is item active
3308 * @cfg {Boolean} disabled Is item disabled
3310 * @cfg {Boolean} preventDefault (true | false) default false
3311 * @cfg {String} tabId the tab that this item activates.
3312 * @cfg {String} tagtype (a|span) render as a href or span?
3315 * Create a new Navbar Item
3316 * @param {Object} config The config object
3318 Roo.bootstrap.NavItem = function(config){
3319 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3324 * The raw click event for the entire grid.
3325 * @param {Roo.EventObject} e
3330 * Fires when the active item active state changes
3331 * @param {Roo.bootstrap.NavItem} this
3332 * @param {boolean} state the new state
3340 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3348 preventDefault : false,
3353 getAutoCreate : function(){
3361 href : this.href || "#",
3362 html: this.html || ''
3368 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3371 // glyphicon and icon go before content..
3372 if (this.glyphicon || this.icon) {
3374 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3376 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3384 cfg.cn[0].html += " <span class='caret'></span>";
3388 if (this.badge !== '') {
3390 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3392 if (this.disabled) {
3393 cfg.cls += ' disabled';
3399 initEvents: function() {
3400 // Roo.log('init events?');
3401 // Roo.log(this.el.dom);
3402 if (typeof (this.menu) != 'undefined') {
3403 this.menu.parentType = this.xtype;
3404 this.menu.triggerEl = this.el;
3405 this.addxtype(Roo.apply({}, this.menu));
3409 this.el.select('a',true).on('click', this.onClick, this);
3410 // at this point parent should be available..
3411 this.parent().register(this);
3414 onClick : function(e)
3417 if(this.preventDefault){
3420 if (this.disabled) {
3423 Roo.log("fire event clicked");
3424 if(this.fireEvent('click', this, e) === false){
3428 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3429 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3430 this.parent().setActiveItem(this);
3438 isActive: function () {
3441 setActive : function(state, fire)
3443 this.active = state;
3445 this.el.removeClass('active');
3446 } else if (!this.el.hasClass('active')) {
3447 this.el.addClass('active');
3450 this.fireEvent('changed', this, state);
3455 // this should not be here...
3456 setDisabled : function(state)
3458 this.disabled = state;
3460 this.el.removeClass('disabled');
3461 } else if (!this.el.hasClass('disabled')) {
3462 this.el.addClass('disabled');
3475 * <span> icon </span>
3476 * <span> text </span>
3477 * <span>badge </span>
3481 * @class Roo.bootstrap.NavSidebarItem
3482 * @extends Roo.bootstrap.NavItem
3483 * Bootstrap Navbar.NavSidebarItem class
3485 * Create a new Navbar Button
3486 * @param {Object} config The config object
3488 Roo.bootstrap.NavSidebarItem = function(config){
3489 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3494 * The raw click event for the entire grid.
3495 * @param {Roo.EventObject} e
3500 * Fires when the active item active state changes
3501 * @param {Roo.bootstrap.NavSidebarItem} this
3502 * @param {boolean} state the new state
3510 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3513 getAutoCreate : function(){
3518 href : this.href || '#',
3530 html : this.html || ''
3535 cfg.cls += ' active';
3539 if (this.glyphicon || this.icon) {
3540 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3541 a.cn.push({ tag : 'i', cls : c }) ;
3546 if (this.badge !== '') {
3547 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3551 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3552 a.cls += 'dropdown-toggle treeview' ;
3576 * @class Roo.bootstrap.Row
3577 * @extends Roo.bootstrap.Component
3578 * Bootstrap Row class (contains columns...)
3582 * @param {Object} config The config object
3585 Roo.bootstrap.Row = function(config){
3586 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3589 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3591 getAutoCreate : function(){
3610 * @class Roo.bootstrap.Element
3611 * @extends Roo.bootstrap.Component
3612 * Bootstrap Element class
3613 * @cfg {String} html contents of the element
3614 * @cfg {String} tag tag of the element
3615 * @cfg {String} cls class of the element
3618 * Create a new Element
3619 * @param {Object} config The config object
3622 Roo.bootstrap.Element = function(config){
3623 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3626 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3633 getAutoCreate : function(){
3658 * @class Roo.bootstrap.Pagination
3659 * @extends Roo.bootstrap.Component
3660 * Bootstrap Pagination class
3661 * @cfg {String} size xs | sm | md | lg
3662 * @cfg {Boolean} inverse false | true
3665 * Create a new Pagination
3666 * @param {Object} config The config object
3669 Roo.bootstrap.Pagination = function(config){
3670 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3673 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3679 getAutoCreate : function(){
3685 cfg.cls += ' inverse';
3691 cfg.cls += " " + this.cls;
3709 * @class Roo.bootstrap.PaginationItem
3710 * @extends Roo.bootstrap.Component
3711 * Bootstrap PaginationItem class
3712 * @cfg {String} html text
3713 * @cfg {String} href the link
3714 * @cfg {Boolean} preventDefault (true | false) default true
3715 * @cfg {Boolean} active (true | false) default false
3719 * Create a new PaginationItem
3720 * @param {Object} config The config object
3724 Roo.bootstrap.PaginationItem = function(config){
3725 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3730 * The raw click event for the entire grid.
3731 * @param {Roo.EventObject} e
3737 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3741 preventDefault: true,
3745 getAutoCreate : function(){
3751 href : this.href ? this.href : '#',
3752 html : this.html ? this.html : ''
3762 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3768 initEvents: function() {
3770 this.el.on('click', this.onClick, this);
3773 onClick : function(e)
3775 Roo.log('PaginationItem on click ');
3776 if(this.preventDefault){
3780 this.fireEvent('click', this, e);
3796 * @class Roo.bootstrap.Slider
3797 * @extends Roo.bootstrap.Component
3798 * Bootstrap Slider class
3801 * Create a new Slider
3802 * @param {Object} config The config object
3805 Roo.bootstrap.Slider = function(config){
3806 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3809 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3811 getAutoCreate : function(){
3815 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3819 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3831 * Ext JS Library 1.1.1
3832 * Copyright(c) 2006-2007, Ext JS, LLC.
3834 * Originally Released Under LGPL - original licence link has changed is not relivant.
3837 * <script type="text/javascript">
3842 * @class Roo.grid.ColumnModel
3843 * @extends Roo.util.Observable
3844 * This is the default implementation of a ColumnModel used by the Grid. It defines
3845 * the columns in the grid.
3848 var colModel = new Roo.grid.ColumnModel([
3849 {header: "Ticker", width: 60, sortable: true, locked: true},
3850 {header: "Company Name", width: 150, sortable: true},
3851 {header: "Market Cap.", width: 100, sortable: true},
3852 {header: "$ Sales", width: 100, sortable: true, renderer: money},
3853 {header: "Employees", width: 100, sortable: true, resizable: false}
3858 * The config options listed for this class are options which may appear in each
3859 * individual column definition.
3860 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
3862 * @param {Object} config An Array of column config objects. See this class's
3863 * config objects for details.
3865 Roo.grid.ColumnModel = function(config){
3867 * The config passed into the constructor
3869 this.config = config;
3872 // if no id, create one
3873 // if the column does not have a dataIndex mapping,
3874 // map it to the order it is in the config
3875 for(var i = 0, len = config.length; i < len; i++){
3877 if(typeof c.dataIndex == "undefined"){
3880 if(typeof c.renderer == "string"){
3881 c.renderer = Roo.util.Format[c.renderer];
3883 if(typeof c.id == "undefined"){
3886 if(c.editor && c.editor.xtype){
3887 c.editor = Roo.factory(c.editor, Roo.grid);
3889 if(c.editor && c.editor.isFormField){
3890 c.editor = new Roo.grid.GridEditor(c.editor);
3892 this.lookup[c.id] = c;
3896 * The width of columns which have no width specified (defaults to 100)
3899 this.defaultWidth = 100;
3902 * Default sortable of columns which have no sortable specified (defaults to false)
3905 this.defaultSortable = false;
3909 * @event widthchange
3910 * Fires when the width of a column changes.
3911 * @param {ColumnModel} this
3912 * @param {Number} columnIndex The column index
3913 * @param {Number} newWidth The new width
3915 "widthchange": true,
3917 * @event headerchange
3918 * Fires when the text of a header changes.
3919 * @param {ColumnModel} this
3920 * @param {Number} columnIndex The column index
3921 * @param {Number} newText The new header text
3923 "headerchange": true,
3925 * @event hiddenchange
3926 * Fires when a column is hidden or "unhidden".
3927 * @param {ColumnModel} this
3928 * @param {Number} columnIndex The column index
3929 * @param {Boolean} hidden true if hidden, false otherwise
3931 "hiddenchange": true,
3933 * @event columnmoved
3934 * Fires when a column is moved.
3935 * @param {ColumnModel} this
3936 * @param {Number} oldIndex
3937 * @param {Number} newIndex
3939 "columnmoved" : true,
3941 * @event columlockchange
3942 * Fires when a column's locked state is changed
3943 * @param {ColumnModel} this
3944 * @param {Number} colIndex
3945 * @param {Boolean} locked true if locked
3947 "columnlockchange" : true
3949 Roo.grid.ColumnModel.superclass.constructor.call(this);
3951 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
3953 * @cfg {String} header The header text to display in the Grid view.
3956 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
3957 * {@link Roo.data.Record} definition from which to draw the column's value. If not
3958 * specified, the column's index is used as an index into the Record's data Array.
3961 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
3962 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
3965 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
3966 * Defaults to the value of the {@link #defaultSortable} property.
3967 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
3970 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
3973 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
3976 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
3979 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
3982 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
3983 * given the cell's data value. See {@link #setRenderer}. If not specified, the
3984 * default renderer uses the raw data value.
3987 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
3990 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
3994 * Returns the id of the column at the specified index.
3995 * @param {Number} index The column index
3996 * @return {String} the id
3998 getColumnId : function(index){
3999 return this.config[index].id;
4003 * Returns the column for a specified id.
4004 * @param {String} id The column id
4005 * @return {Object} the column
4007 getColumnById : function(id){
4008 return this.lookup[id];
4013 * Returns the column for a specified dataIndex.
4014 * @param {String} dataIndex The column dataIndex
4015 * @return {Object|Boolean} the column or false if not found
4017 getColumnByDataIndex: function(dataIndex){
4018 var index = this.findColumnIndex(dataIndex);
4019 return index > -1 ? this.config[index] : false;
4023 * Returns the index for a specified column id.
4024 * @param {String} id The column id
4025 * @return {Number} the index, or -1 if not found
4027 getIndexById : function(id){
4028 for(var i = 0, len = this.config.length; i < len; i++){
4029 if(this.config[i].id == id){
4037 * Returns the index for a specified column dataIndex.
4038 * @param {String} dataIndex The column dataIndex
4039 * @return {Number} the index, or -1 if not found
4042 findColumnIndex : function(dataIndex){
4043 for(var i = 0, len = this.config.length; i < len; i++){
4044 if(this.config[i].dataIndex == dataIndex){
4052 moveColumn : function(oldIndex, newIndex){
4053 var c = this.config[oldIndex];
4054 this.config.splice(oldIndex, 1);
4055 this.config.splice(newIndex, 0, c);
4056 this.dataMap = null;
4057 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4060 isLocked : function(colIndex){
4061 return this.config[colIndex].locked === true;
4064 setLocked : function(colIndex, value, suppressEvent){
4065 if(this.isLocked(colIndex) == value){
4068 this.config[colIndex].locked = value;
4070 this.fireEvent("columnlockchange", this, colIndex, value);
4074 getTotalLockedWidth : function(){
4076 for(var i = 0; i < this.config.length; i++){
4077 if(this.isLocked(i) && !this.isHidden(i)){
4078 this.totalWidth += this.getColumnWidth(i);
4084 getLockedCount : function(){
4085 for(var i = 0, len = this.config.length; i < len; i++){
4086 if(!this.isLocked(i)){
4093 * Returns the number of columns.
4096 getColumnCount : function(visibleOnly){
4097 if(visibleOnly === true){
4099 for(var i = 0, len = this.config.length; i < len; i++){
4100 if(!this.isHidden(i)){
4106 return this.config.length;
4110 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4111 * @param {Function} fn
4112 * @param {Object} scope (optional)
4113 * @return {Array} result
4115 getColumnsBy : function(fn, scope){
4117 for(var i = 0, len = this.config.length; i < len; i++){
4118 var c = this.config[i];
4119 if(fn.call(scope||this, c, i) === true){
4127 * Returns true if the specified column is sortable.
4128 * @param {Number} col The column index
4131 isSortable : function(col){
4132 if(typeof this.config[col].sortable == "undefined"){
4133 return this.defaultSortable;
4135 return this.config[col].sortable;
4139 * Returns the rendering (formatting) function defined for the column.
4140 * @param {Number} col The column index.
4141 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4143 getRenderer : function(col){
4144 if(!this.config[col].renderer){
4145 return Roo.grid.ColumnModel.defaultRenderer;
4147 return this.config[col].renderer;
4151 * Sets the rendering (formatting) function for a column.
4152 * @param {Number} col The column index
4153 * @param {Function} fn The function to use to process the cell's raw data
4154 * to return HTML markup for the grid view. The render function is called with
4155 * the following parameters:<ul>
4156 * <li>Data value.</li>
4157 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4158 * <li>css A CSS style string to apply to the table cell.</li>
4159 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4160 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4161 * <li>Row index</li>
4162 * <li>Column index</li>
4163 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4165 setRenderer : function(col, fn){
4166 this.config[col].renderer = fn;
4170 * Returns the width for the specified column.
4171 * @param {Number} col The column index
4174 getColumnWidth : function(col){
4175 return this.config[col].width * 1 || this.defaultWidth;
4179 * Sets the width for a column.
4180 * @param {Number} col The column index
4181 * @param {Number} width The new width
4183 setColumnWidth : function(col, width, suppressEvent){
4184 this.config[col].width = width;
4185 this.totalWidth = null;
4187 this.fireEvent("widthchange", this, col, width);
4192 * Returns the total width of all columns.
4193 * @param {Boolean} includeHidden True to include hidden column widths
4196 getTotalWidth : function(includeHidden){
4197 if(!this.totalWidth){
4198 this.totalWidth = 0;
4199 for(var i = 0, len = this.config.length; i < len; i++){
4200 if(includeHidden || !this.isHidden(i)){
4201 this.totalWidth += this.getColumnWidth(i);
4205 return this.totalWidth;
4209 * Returns the header for the specified column.
4210 * @param {Number} col The column index
4213 getColumnHeader : function(col){
4214 return this.config[col].header;
4218 * Sets the header for a column.
4219 * @param {Number} col The column index
4220 * @param {String} header The new header
4222 setColumnHeader : function(col, header){
4223 this.config[col].header = header;
4224 this.fireEvent("headerchange", this, col, header);
4228 * Returns the tooltip for the specified column.
4229 * @param {Number} col The column index
4232 getColumnTooltip : function(col){
4233 return this.config[col].tooltip;
4236 * Sets the tooltip for a column.
4237 * @param {Number} col The column index
4238 * @param {String} tooltip The new tooltip
4240 setColumnTooltip : function(col, tooltip){
4241 this.config[col].tooltip = tooltip;
4245 * Returns the dataIndex for the specified column.
4246 * @param {Number} col The column index
4249 getDataIndex : function(col){
4250 return this.config[col].dataIndex;
4254 * Sets the dataIndex for a column.
4255 * @param {Number} col The column index
4256 * @param {Number} dataIndex The new dataIndex
4258 setDataIndex : function(col, dataIndex){
4259 this.config[col].dataIndex = dataIndex;
4265 * Returns true if the cell is editable.
4266 * @param {Number} colIndex The column index
4267 * @param {Number} rowIndex The row index
4270 isCellEditable : function(colIndex, rowIndex){
4271 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4275 * Returns the editor defined for the cell/column.
4276 * return false or null to disable editing.
4277 * @param {Number} colIndex The column index
4278 * @param {Number} rowIndex The row index
4281 getCellEditor : function(colIndex, rowIndex){
4282 return this.config[colIndex].editor;
4286 * Sets if a column is editable.
4287 * @param {Number} col The column index
4288 * @param {Boolean} editable True if the column is editable
4290 setEditable : function(col, editable){
4291 this.config[col].editable = editable;
4296 * Returns true if the column is hidden.
4297 * @param {Number} colIndex The column index
4300 isHidden : function(colIndex){
4301 return this.config[colIndex].hidden;
4306 * Returns true if the column width cannot be changed
4308 isFixed : function(colIndex){
4309 return this.config[colIndex].fixed;
4313 * Returns true if the column can be resized
4316 isResizable : function(colIndex){
4317 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4320 * Sets if a column is hidden.
4321 * @param {Number} colIndex The column index
4322 * @param {Boolean} hidden True if the column is hidden
4324 setHidden : function(colIndex, hidden){
4325 this.config[colIndex].hidden = hidden;
4326 this.totalWidth = null;
4327 this.fireEvent("hiddenchange", this, colIndex, hidden);
4331 * Sets the editor for a column.
4332 * @param {Number} col The column index
4333 * @param {Object} editor The editor object
4335 setEditor : function(col, editor){
4336 this.config[col].editor = editor;
4340 Roo.grid.ColumnModel.defaultRenderer = function(value){
4341 if(typeof value == "string" && value.length < 1){
4347 // Alias for backwards compatibility
4348 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4351 * Ext JS Library 1.1.1
4352 * Copyright(c) 2006-2007, Ext JS, LLC.
4354 * Originally Released Under LGPL - original licence link has changed is not relivant.
4357 * <script type="text/javascript">
4361 * @class Roo.LoadMask
4362 * A simple utility class for generically masking elements while loading data. If the element being masked has
4363 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4364 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4365 * element's UpdateManager load indicator and will be destroyed after the initial load.
4367 * Create a new LoadMask
4368 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4369 * @param {Object} config The config object
4371 Roo.LoadMask = function(el, config){
4372 this.el = Roo.get(el);
4373 Roo.apply(this, config);
4375 this.store.on('beforeload', this.onBeforeLoad, this);
4376 this.store.on('load', this.onLoad, this);
4377 this.store.on('loadexception', this.onLoadException, this);
4378 this.removeMask = false;
4380 var um = this.el.getUpdateManager();
4381 um.showLoadIndicator = false; // disable the default indicator
4382 um.on('beforeupdate', this.onBeforeLoad, this);
4383 um.on('update', this.onLoad, this);
4384 um.on('failure', this.onLoad, this);
4385 this.removeMask = true;
4389 Roo.LoadMask.prototype = {
4391 * @cfg {Boolean} removeMask
4392 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4393 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4397 * The text to display in a centered loading message box (defaults to 'Loading...')
4401 * @cfg {String} msgCls
4402 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4404 msgCls : 'x-mask-loading',
4407 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4413 * Disables the mask to prevent it from being displayed
4415 disable : function(){
4416 this.disabled = true;
4420 * Enables the mask so that it can be displayed
4422 enable : function(){
4423 this.disabled = false;
4426 onLoadException : function()
4430 if (typeof(arguments[3]) != 'undefined') {
4431 Roo.MessageBox.alert("Error loading",arguments[3]);
4435 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4436 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4445 this.el.unmask(this.removeMask);
4450 this.el.unmask(this.removeMask);
4454 onBeforeLoad : function(){
4456 this.el.mask(this.msg, this.msgCls);
4461 destroy : function(){
4463 this.store.un('beforeload', this.onBeforeLoad, this);
4464 this.store.un('load', this.onLoad, this);
4465 this.store.un('loadexception', this.onLoadException, this);
4467 var um = this.el.getUpdateManager();
4468 um.un('beforeupdate', this.onBeforeLoad, this);
4469 um.un('update', this.onLoad, this);
4470 um.un('failure', this.onLoad, this);
4481 * @class Roo.bootstrap.Table
4482 * @extends Roo.bootstrap.Component
4483 * Bootstrap Table class
4484 * @cfg {String} cls table class
4485 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4486 * @cfg {String} bgcolor Specifies the background color for a table
4487 * @cfg {Number} border Specifies whether the table cells should have borders or not
4488 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4489 * @cfg {Number} cellspacing Specifies the space between cells
4490 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4491 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4492 * @cfg {String} sortable Specifies that the table should be sortable
4493 * @cfg {String} summary Specifies a summary of the content of a table
4494 * @cfg {Number} width Specifies the width of a table
4496 * @cfg {boolean} striped Should the rows be alternative striped
4497 * @cfg {boolean} bordered Add borders to the table
4498 * @cfg {boolean} hover Add hover highlighting
4499 * @cfg {boolean} condensed Format condensed
4500 * @cfg {boolean} responsive Format condensed
4501 * @cfg {Boolean} loadMask (true|false) default false
4502 * @cfg {Boolean} tfoor (true|false) generate tfoot, default true
4503 * @cfg {Boolean} thead (true|false) generate thead, default true
4505 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4509 * Create a new Table
4510 * @param {Object} config The config object
4513 Roo.bootstrap.Table = function(config){
4514 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4517 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4518 this.sm = this.selModel;
4519 this.sm.xmodule = this.xmodule || false;
4521 if (this.cm && typeof(this.cm.config) == 'undefined') {
4522 this.colModel = new Roo.grid.ColumnModel(this.cm);
4523 this.cm = this.colModel;
4524 this.cm.xmodule = this.xmodule || false;
4527 this.store= Roo.factory(this.store, Roo.data);
4528 this.ds = this.store;
4529 this.ds.xmodule = this.xmodule || false;
4532 if (this.footer && this.store) {
4533 this.footer.dataSource = this.ds;
4534 this.footer = Roo.factory(this.footer);
4538 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4563 getAutoCreate : function(){
4564 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4573 cfg.cls += ' table-striped';
4576 cfg.cls += ' table-hover';
4578 if (this.bordered) {
4579 cfg.cls += ' table-bordered';
4581 if (this.condensed) {
4582 cfg.cls += ' table-condensed';
4584 if (this.responsive) {
4585 cfg.cls += ' table-responsive';
4592 cfg.cls+= ' ' +this.cls;
4595 // this lot should be simplifed...
4598 cfg.align=this.align;
4601 cfg.bgcolor=this.bgcolor;
4604 cfg.border=this.border;
4606 if (this.cellpadding) {
4607 cfg.cellpadding=this.cellpadding;
4609 if (this.cellspacing) {
4610 cfg.cellspacing=this.cellspacing;
4613 cfg.frame=this.frame;
4616 cfg.rules=this.rules;
4618 if (this.sortable) {
4619 cfg.sortable=this.sortable;
4622 cfg.summary=this.summary;
4625 cfg.width=this.width;
4628 if(this.store || this.cm){
4630 cfg.cn.push(this.renderHeader());
4633 cfg.cn.push(this.renderBody());
4636 cfg.cn.push(this.renderFooter());
4639 cfg.cls+= ' TableGrid';
4643 return { cn : [ cfg ] };
4646 // initTableGrid : function()
4655 // var cm = this.cm;
4657 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4660 // html: cm.getColumnHeader(i)
4664 // cfg.push(header);
4671 initEvents : function()
4673 if(!this.store || !this.cm){
4677 Roo.log('initEvents with ds!!!!');
4681 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4682 e.on('click', _this.sort, _this);
4684 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
4685 // this.maskEl.enableDisplayMode("block");
4686 // this.maskEl.show();
4688 this.parent().el.setStyle('position', 'relative');
4690 this.footer.parentId = this.id;
4691 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4695 // mask should be using Roo.bootstrap.Mask...
4700 style: "text-align:center",
4704 style: "background-color:white;width:50%;margin:100 auto",
4708 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
4720 var size = this.el.getSize();
4722 this.maskEl = Roo.DomHelper.append(document.body, mark, true);
4724 this.maskEl.setSize(size.width, 300); // we will fix the height at the beginning...
4725 this.maskEl.enableDisplayMode("block");
4727 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4729 this.store.on('load', this.onLoad, this);
4730 this.store.on('beforeload', this.onBeforeLoad, this);
4732 // load should be trigger on render..
4733 //this.store.load();
4739 sort : function(e,el)
4741 var col = Roo.get(el)
4743 if(!col.hasClass('sortable')){
4747 var sort = col.attr('sort');
4750 if(col.hasClass('glyphicon-arrow-up')){
4754 this.store.sortInfo = {field : sort, direction : dir};
4757 Roo.log("calling footer first");
4758 this.footer.onClick('first');
4761 this.store.load({ params : { start : 0 } });
4765 renderHeader : function()
4774 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4776 var config = cm.config[i];
4778 if(typeof(config.hidden) != 'undefined' && config.hidden){
4785 html: cm.getColumnHeader(i)
4788 if(typeof(config.dataIndex) != 'undefined'){
4789 c.sort = config.dataIndex;
4792 if(typeof(config.sortable) != 'undefined' && config.sortable){
4796 // if(typeof(config.align) != 'undefined' && config.align.length){
4797 // c.style += ' text-align:' + config.align + ';';
4800 if(typeof(config.width) != 'undefined'){
4801 c.style += 'width:' + config.width + 'px;';
4810 renderBody : function()
4820 colspan : this.cm.getColumnCount()
4830 renderFooter : function()
4840 colspan : this.cm.getColumnCount()
4852 Roo.log('ds onload');
4858 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4859 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4861 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4862 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4865 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4866 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4870 var tbody = this.el.select('tbody', true).first();
4874 if(this.store.getCount() > 0){
4875 this.store.data.each(function(d){
4881 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4882 var config = cm.config[i];
4884 if(typeof(config.hidden) != 'undefined' && config.hidden){
4888 var renderer = cm.getRenderer(i);
4892 if(typeof(renderer) !== 'undefined'){
4893 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4896 if(typeof(value) === 'object'){
4907 html: (typeof(value) === 'object') ? '' : value
4910 if(typeof(config.align) != 'undefined' && config.align.length){
4911 td.style += ' text-align:' + config.align + ';';
4914 if(typeof(config.width) != 'undefined'){
4915 td.style += 'width:' + config.width + 'px;';
4923 tbody.createChild(row);
4931 Roo.each(renders, function(r){
4932 _this.renderColumn(r);
4936 //if(this.loadMask){
4937 // this.maskEl.hide();
4941 onBeforeLoad : function()
4943 //Roo.log('ds onBeforeLoad');
4947 //if(this.loadMask){
4948 // this.maskEl.show();
4954 this.el.select('tbody', true).first().dom.innerHTML = '';
4957 getSelectionModel : function(){
4959 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4961 return this.selModel;
4964 renderColumn : function(r)
4967 r.cfg.render(Roo.get(r.id));
4970 Roo.each(r.cfg.cn, function(c){
4975 _this.renderColumn(child);
4992 * @class Roo.bootstrap.TableCell
4993 * @extends Roo.bootstrap.Component
4994 * Bootstrap TableCell class
4995 * @cfg {String} html cell contain text
4996 * @cfg {String} cls cell class
4997 * @cfg {String} tag cell tag (td|th) default td
4998 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4999 * @cfg {String} align Aligns the content in a cell
5000 * @cfg {String} axis Categorizes cells
5001 * @cfg {String} bgcolor Specifies the background color of a cell
5002 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5003 * @cfg {Number} colspan Specifies the number of columns a cell should span
5004 * @cfg {String} headers Specifies one or more header cells a cell is related to
5005 * @cfg {Number} height Sets the height of a cell
5006 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5007 * @cfg {Number} rowspan Sets the number of rows a cell should span
5008 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5009 * @cfg {String} valign Vertical aligns the content in a cell
5010 * @cfg {Number} width Specifies the width of a cell
5013 * Create a new TableCell
5014 * @param {Object} config The config object
5017 Roo.bootstrap.TableCell = function(config){
5018 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5021 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5041 getAutoCreate : function(){
5042 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5062 cfg.align=this.align
5068 cfg.bgcolor=this.bgcolor
5071 cfg.charoff=this.charoff
5074 cfg.colspan=this.colspan
5077 cfg.headers=this.headers
5080 cfg.height=this.height
5083 cfg.nowrap=this.nowrap
5086 cfg.rowspan=this.rowspan
5089 cfg.scope=this.scope
5092 cfg.valign=this.valign
5095 cfg.width=this.width
5114 * @class Roo.bootstrap.TableRow
5115 * @extends Roo.bootstrap.Component
5116 * Bootstrap TableRow class
5117 * @cfg {String} cls row class
5118 * @cfg {String} align Aligns the content in a table row
5119 * @cfg {String} bgcolor Specifies a background color for a table row
5120 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5121 * @cfg {String} valign Vertical aligns the content in a table row
5124 * Create a new TableRow
5125 * @param {Object} config The config object
5128 Roo.bootstrap.TableRow = function(config){
5129 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5132 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5140 getAutoCreate : function(){
5141 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5151 cfg.align = this.align;
5154 cfg.bgcolor = this.bgcolor;
5157 cfg.charoff = this.charoff;
5160 cfg.valign = this.valign;
5178 * @class Roo.bootstrap.TableBody
5179 * @extends Roo.bootstrap.Component
5180 * Bootstrap TableBody class
5181 * @cfg {String} cls element class
5182 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5183 * @cfg {String} align Aligns the content inside the element
5184 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5185 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5188 * Create a new TableBody
5189 * @param {Object} config The config object
5192 Roo.bootstrap.TableBody = function(config){
5193 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5196 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5204 getAutoCreate : function(){
5205 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5219 cfg.align = this.align;
5222 cfg.charoff = this.charoff;
5225 cfg.valign = this.valign;
5232 // initEvents : function()
5239 // this.store = Roo.factory(this.store, Roo.data);
5240 // this.store.on('load', this.onLoad, this);
5242 // this.store.load();
5246 // onLoad: function ()
5248 // this.fireEvent('load', this);
5258 * Ext JS Library 1.1.1
5259 * Copyright(c) 2006-2007, Ext JS, LLC.
5261 * Originally Released Under LGPL - original licence link has changed is not relivant.
5264 * <script type="text/javascript">
5267 // as we use this in bootstrap.
5268 Roo.namespace('Roo.form');
5270 * @class Roo.form.Action
5271 * Internal Class used to handle form actions
5273 * @param {Roo.form.BasicForm} el The form element or its id
5274 * @param {Object} config Configuration options
5279 // define the action interface
5280 Roo.form.Action = function(form, options){
5282 this.options = options || {};
5285 * Client Validation Failed
5288 Roo.form.Action.CLIENT_INVALID = 'client';
5290 * Server Validation Failed
5293 Roo.form.Action.SERVER_INVALID = 'server';
5295 * Connect to Server Failed
5298 Roo.form.Action.CONNECT_FAILURE = 'connect';
5300 * Reading Data from Server Failed
5303 Roo.form.Action.LOAD_FAILURE = 'load';
5305 Roo.form.Action.prototype = {
5307 failureType : undefined,
5308 response : undefined,
5312 run : function(options){
5317 success : function(response){
5322 handleResponse : function(response){
5326 // default connection failure
5327 failure : function(response){
5329 this.response = response;
5330 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5331 this.form.afterAction(this, false);
5334 processResponse : function(response){
5335 this.response = response;
5336 if(!response.responseText){
5339 this.result = this.handleResponse(response);
5343 // utility functions used internally
5344 getUrl : function(appendParams){
5345 var url = this.options.url || this.form.url || this.form.el.dom.action;
5347 var p = this.getParams();
5349 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5355 getMethod : function(){
5356 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5359 getParams : function(){
5360 var bp = this.form.baseParams;
5361 var p = this.options.params;
5363 if(typeof p == "object"){
5364 p = Roo.urlEncode(Roo.applyIf(p, bp));
5365 }else if(typeof p == 'string' && bp){
5366 p += '&' + Roo.urlEncode(bp);
5369 p = Roo.urlEncode(bp);
5374 createCallback : function(){
5376 success: this.success,
5377 failure: this.failure,
5379 timeout: (this.form.timeout*1000),
5380 upload: this.form.fileUpload ? this.success : undefined
5385 Roo.form.Action.Submit = function(form, options){
5386 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5389 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5392 haveProgress : false,
5393 uploadComplete : false,
5395 // uploadProgress indicator.
5396 uploadProgress : function()
5398 if (!this.form.progressUrl) {
5402 if (!this.haveProgress) {
5403 Roo.MessageBox.progress("Uploading", "Uploading");
5405 if (this.uploadComplete) {
5406 Roo.MessageBox.hide();
5410 this.haveProgress = true;
5412 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5414 var c = new Roo.data.Connection();
5416 url : this.form.progressUrl,
5421 success : function(req){
5422 //console.log(data);
5426 rdata = Roo.decode(req.responseText)
5428 Roo.log("Invalid data from server..");
5432 if (!rdata || !rdata.success) {
5434 Roo.MessageBox.alert(Roo.encode(rdata));
5437 var data = rdata.data;
5439 if (this.uploadComplete) {
5440 Roo.MessageBox.hide();
5445 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5446 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5449 this.uploadProgress.defer(2000,this);
5452 failure: function(data) {
5453 Roo.log('progress url failed ');
5464 // run get Values on the form, so it syncs any secondary forms.
5465 this.form.getValues();
5467 var o = this.options;
5468 var method = this.getMethod();
5469 var isPost = method == 'POST';
5470 if(o.clientValidation === false || this.form.isValid()){
5472 if (this.form.progressUrl) {
5473 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5474 (new Date() * 1) + '' + Math.random());
5479 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5480 form:this.form.el.dom,
5481 url:this.getUrl(!isPost),
5483 params:isPost ? this.getParams() : null,
5484 isUpload: this.form.fileUpload
5487 this.uploadProgress();
5489 }else if (o.clientValidation !== false){ // client validation failed
5490 this.failureType = Roo.form.Action.CLIENT_INVALID;
5491 this.form.afterAction(this, false);
5495 success : function(response)
5497 this.uploadComplete= true;
5498 if (this.haveProgress) {
5499 Roo.MessageBox.hide();
5503 var result = this.processResponse(response);
5504 if(result === true || result.success){
5505 this.form.afterAction(this, true);
5509 this.form.markInvalid(result.errors);
5510 this.failureType = Roo.form.Action.SERVER_INVALID;
5512 this.form.afterAction(this, false);
5514 failure : function(response)
5516 this.uploadComplete= true;
5517 if (this.haveProgress) {
5518 Roo.MessageBox.hide();
5521 this.response = response;
5522 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5523 this.form.afterAction(this, false);
5526 handleResponse : function(response){
5527 if(this.form.errorReader){
5528 var rs = this.form.errorReader.read(response);
5531 for(var i = 0, len = rs.records.length; i < len; i++) {
5532 var r = rs.records[i];
5536 if(errors.length < 1){
5540 success : rs.success,
5546 ret = Roo.decode(response.responseText);
5550 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5560 Roo.form.Action.Load = function(form, options){
5561 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5562 this.reader = this.form.reader;
5565 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5570 Roo.Ajax.request(Roo.apply(
5571 this.createCallback(), {
5572 method:this.getMethod(),
5573 url:this.getUrl(false),
5574 params:this.getParams()
5578 success : function(response){
5580 var result = this.processResponse(response);
5581 if(result === true || !result.success || !result.data){
5582 this.failureType = Roo.form.Action.LOAD_FAILURE;
5583 this.form.afterAction(this, false);
5586 this.form.clearInvalid();
5587 this.form.setValues(result.data);
5588 this.form.afterAction(this, true);
5591 handleResponse : function(response){
5592 if(this.form.reader){
5593 var rs = this.form.reader.read(response);
5594 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5596 success : rs.success,
5600 return Roo.decode(response.responseText);
5604 Roo.form.Action.ACTION_TYPES = {
5605 'load' : Roo.form.Action.Load,
5606 'submit' : Roo.form.Action.Submit
5615 * @class Roo.bootstrap.Form
5616 * @extends Roo.bootstrap.Component
5617 * Bootstrap Form class
5618 * @cfg {String} method GET | POST (default POST)
5619 * @cfg {String} labelAlign top | left (default top)
5620 * @cfg {String} align left | right - for navbars
5625 * @param {Object} config The config object
5629 Roo.bootstrap.Form = function(config){
5630 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5633 * @event clientvalidation
5634 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5635 * @param {Form} this
5636 * @param {Boolean} valid true if the form has passed client-side validation
5638 clientvalidation: true,
5640 * @event beforeaction
5641 * Fires before any action is performed. Return false to cancel the action.
5642 * @param {Form} this
5643 * @param {Action} action The action to be performed
5647 * @event actionfailed
5648 * Fires when an action fails.
5649 * @param {Form} this
5650 * @param {Action} action The action that failed
5652 actionfailed : true,
5654 * @event actioncomplete
5655 * Fires when an action is completed.
5656 * @param {Form} this
5657 * @param {Action} action The action that completed
5659 actioncomplete : true
5664 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5667 * @cfg {String} method
5668 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5673 * The URL to use for form actions if one isn't supplied in the action options.
5676 * @cfg {Boolean} fileUpload
5677 * Set to true if this form is a file upload.
5681 * @cfg {Object} baseParams
5682 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5686 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5690 * @cfg {Sting} align (left|right) for navbar forms
5695 activeAction : null,
5698 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5699 * element by passing it or its id or mask the form itself by passing in true.
5702 waitMsgTarget : false,
5707 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5708 * element by passing it or its id or mask the form itself by passing in true.
5712 getAutoCreate : function(){
5716 method : this.method || 'POST',
5717 id : this.id || Roo.id(),
5720 if (this.parent().xtype.match(/^Nav/)) {
5721 cfg.cls = 'navbar-form navbar-' + this.align;
5725 if (this.labelAlign == 'left' ) {
5726 cfg.cls += ' form-horizontal';
5732 initEvents : function()
5734 this.el.on('submit', this.onSubmit, this);
5739 onSubmit : function(e){
5744 * Returns true if client-side validation on the form is successful.
5747 isValid : function(){
5748 var items = this.getItems();
5750 items.each(function(f){
5759 * Returns true if any fields in this form have changed since their original load.
5762 isDirty : function(){
5764 var items = this.getItems();
5765 items.each(function(f){
5775 * Performs a predefined action (submit or load) or custom actions you define on this form.
5776 * @param {String} actionName The name of the action type
5777 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5778 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5779 * accept other config options):
5781 Property Type Description
5782 ---------------- --------------- ----------------------------------------------------------------------------------
5783 url String The url for the action (defaults to the form's url)
5784 method String The form method to use (defaults to the form's method, or POST if not defined)
5785 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5786 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5787 validate the form on the client (defaults to false)
5789 * @return {BasicForm} this
5791 doAction : function(action, options){
5792 if(typeof action == 'string'){
5793 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5795 if(this.fireEvent('beforeaction', this, action) !== false){
5796 this.beforeAction(action);
5797 action.run.defer(100, action);
5803 beforeAction : function(action){
5804 var o = action.options;
5806 // not really supported yet.. ??
5808 //if(this.waitMsgTarget === true){
5809 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5810 //}else if(this.waitMsgTarget){
5811 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5812 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5814 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5820 afterAction : function(action, success){
5821 this.activeAction = null;
5822 var o = action.options;
5824 //if(this.waitMsgTarget === true){
5826 //}else if(this.waitMsgTarget){
5827 // this.waitMsgTarget.unmask();
5829 // Roo.MessageBox.updateProgress(1);
5830 // Roo.MessageBox.hide();
5837 Roo.callback(o.success, o.scope, [this, action]);
5838 this.fireEvent('actioncomplete', this, action);
5842 // failure condition..
5843 // we have a scenario where updates need confirming.
5844 // eg. if a locking scenario exists..
5845 // we look for { errors : { needs_confirm : true }} in the response.
5847 (typeof(action.result) != 'undefined') &&
5848 (typeof(action.result.errors) != 'undefined') &&
5849 (typeof(action.result.errors.needs_confirm) != 'undefined')
5852 Roo.log("not supported yet");
5855 Roo.MessageBox.confirm(
5856 "Change requires confirmation",
5857 action.result.errorMsg,
5862 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5872 Roo.callback(o.failure, o.scope, [this, action]);
5873 // show an error message if no failed handler is set..
5874 if (!this.hasListener('actionfailed')) {
5875 Roo.log("need to add dialog support");
5877 Roo.MessageBox.alert("Error",
5878 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5879 action.result.errorMsg :
5880 "Saving Failed, please check your entries or try again"
5885 this.fireEvent('actionfailed', this, action);
5890 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5891 * @param {String} id The value to search for
5894 findField : function(id){
5895 var items = this.getItems();
5896 var field = items.get(id);
5898 items.each(function(f){
5899 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5906 return field || null;
5909 * Mark fields in this form invalid in bulk.
5910 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5911 * @return {BasicForm} this
5913 markInvalid : function(errors){
5914 if(errors instanceof Array){
5915 for(var i = 0, len = errors.length; i < len; i++){
5916 var fieldError = errors[i];
5917 var f = this.findField(fieldError.id);
5919 f.markInvalid(fieldError.msg);
5925 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5926 field.markInvalid(errors[id]);
5930 //Roo.each(this.childForms || [], function (f) {
5931 // f.markInvalid(errors);
5938 * Set values for fields in this form in bulk.
5939 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5940 * @return {BasicForm} this
5942 setValues : function(values){
5943 if(values instanceof Array){ // array of objects
5944 for(var i = 0, len = values.length; i < len; i++){
5946 var f = this.findField(v.id);
5948 f.setValue(v.value);
5949 if(this.trackResetOnLoad){
5950 f.originalValue = f.getValue();
5954 }else{ // object hash
5957 if(typeof values[id] != 'function' && (field = this.findField(id))){
5959 if (field.setFromData &&
5961 field.displayField &&
5962 // combos' with local stores can
5963 // be queried via setValue()
5964 // to set their value..
5965 (field.store && !field.store.isLocal)
5969 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5970 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5971 field.setFromData(sd);
5974 field.setValue(values[id]);
5978 if(this.trackResetOnLoad){
5979 field.originalValue = field.getValue();
5985 //Roo.each(this.childForms || [], function (f) {
5986 // f.setValues(values);
5993 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5994 * they are returned as an array.
5995 * @param {Boolean} asString
5998 getValues : function(asString){
5999 //if (this.childForms) {
6000 // copy values from the child forms
6001 // Roo.each(this.childForms, function (f) {
6002 // this.setValues(f.getValues());
6008 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6009 if(asString === true){
6012 return Roo.urlDecode(fs);
6016 * Returns the fields in this form as an object with key/value pairs.
6017 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6020 getFieldValues : function(with_hidden)
6022 var items = this.getItems();
6024 items.each(function(f){
6028 var v = f.getValue();
6029 if (f.inputType =='radio') {
6030 if (typeof(ret[f.getName()]) == 'undefined') {
6031 ret[f.getName()] = ''; // empty..
6034 if (!f.el.dom.checked) {
6042 // not sure if this supported any more..
6043 if ((typeof(v) == 'object') && f.getRawValue) {
6044 v = f.getRawValue() ; // dates..
6046 // combo boxes where name != hiddenName...
6047 if (f.name != f.getName()) {
6048 ret[f.name] = f.getRawValue();
6050 ret[f.getName()] = v;
6057 * Clears all invalid messages in this form.
6058 * @return {BasicForm} this
6060 clearInvalid : function(){
6061 var items = this.getItems();
6063 items.each(function(f){
6074 * @return {BasicForm} this
6077 var items = this.getItems();
6078 items.each(function(f){
6082 Roo.each(this.childForms || [], function (f) {
6089 getItems : function()
6091 var r=new Roo.util.MixedCollection(false, function(o){
6092 return o.id || (o.id = Roo.id());
6094 var iter = function(el) {
6101 Roo.each(el.items,function(e) {
6120 * Ext JS Library 1.1.1
6121 * Copyright(c) 2006-2007, Ext JS, LLC.
6123 * Originally Released Under LGPL - original licence link has changed is not relivant.
6126 * <script type="text/javascript">
6129 * @class Roo.form.VTypes
6130 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6133 Roo.form.VTypes = function(){
6134 // closure these in so they are only created once.
6135 var alpha = /^[a-zA-Z_]+$/;
6136 var alphanum = /^[a-zA-Z0-9_]+$/;
6137 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6138 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6140 // All these messages and functions are configurable
6143 * The function used to validate email addresses
6144 * @param {String} value The email address
6146 'email' : function(v){
6147 return email.test(v);
6150 * The error text to display when the email validation function returns false
6153 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6155 * The keystroke filter mask to be applied on email input
6158 'emailMask' : /[a-z0-9_\.\-@]/i,
6161 * The function used to validate URLs
6162 * @param {String} value The URL
6164 'url' : function(v){
6168 * The error text to display when the url validation function returns false
6171 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6174 * The function used to validate alpha values
6175 * @param {String} value The value
6177 'alpha' : function(v){
6178 return alpha.test(v);
6181 * The error text to display when the alpha validation function returns false
6184 'alphaText' : 'This field should only contain letters and _',
6186 * The keystroke filter mask to be applied on alpha input
6189 'alphaMask' : /[a-z_]/i,
6192 * The function used to validate alphanumeric values
6193 * @param {String} value The value
6195 'alphanum' : function(v){
6196 return alphanum.test(v);
6199 * The error text to display when the alphanumeric validation function returns false
6202 'alphanumText' : 'This field should only contain letters, numbers and _',
6204 * The keystroke filter mask to be applied on alphanumeric input
6207 'alphanumMask' : /[a-z0-9_]/i
6217 * @class Roo.bootstrap.Input
6218 * @extends Roo.bootstrap.Component
6219 * Bootstrap Input class
6220 * @cfg {Boolean} disabled is it disabled
6221 * @cfg {String} fieldLabel - the label associated
6222 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6223 * @cfg {String} name name of the input
6224 * @cfg {string} fieldLabel - the label associated
6225 * @cfg {string} inputType - input / file submit ...
6226 * @cfg {string} placeholder - placeholder to put in text.
6227 * @cfg {string} before - input group add on before
6228 * @cfg {string} after - input group add on after
6229 * @cfg {string} size - (lg|sm) or leave empty..
6230 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6231 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6232 * @cfg {Number} md colspan out of 12 for computer-sized screens
6233 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6234 * @cfg {string} value default value of the input
6235 * @cfg {Number} labelWidth set the width of label (0-12)
6236 * @cfg {String} labelAlign (top|left)
6237 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6238 * @cfg {String} align (left|center|right) Default left
6242 * Create a new Input
6243 * @param {Object} config The config object
6246 Roo.bootstrap.Input = function(config){
6247 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6252 * Fires when this field receives input focus.
6253 * @param {Roo.form.Field} this
6258 * Fires when this field loses input focus.
6259 * @param {Roo.form.Field} this
6264 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6265 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6266 * @param {Roo.form.Field} this
6267 * @param {Roo.EventObject} e The event object
6272 * Fires just before the field blurs if the field value has changed.
6273 * @param {Roo.form.Field} this
6274 * @param {Mixed} newValue The new value
6275 * @param {Mixed} oldValue The original value
6280 * Fires after the field has been marked as invalid.
6281 * @param {Roo.form.Field} this
6282 * @param {String} msg The validation message
6287 * Fires after the field has been validated with no errors.
6288 * @param {Roo.form.Field} this
6293 * Fires after the key up
6294 * @param {Roo.form.Field} this
6295 * @param {Roo.EventObject} e The event Object
6301 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6303 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6304 automatic validation (defaults to "keyup").
6306 validationEvent : "keyup",
6308 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6310 validateOnBlur : true,
6312 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6314 validationDelay : 250,
6316 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6318 focusClass : "x-form-focus", // not needed???
6322 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6324 invalidClass : "has-error",
6327 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6329 selectOnFocus : false,
6332 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6336 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6341 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6343 disableKeyFilter : false,
6346 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6350 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6354 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6356 blankText : "This field is required",
6359 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6363 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6365 maxLength : Number.MAX_VALUE,
6367 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6369 minLengthText : "The minimum length for this field is {0}",
6371 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6373 maxLengthText : "The maximum length for this field is {0}",
6377 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6378 * If available, this function will be called only after the basic validators all return true, and will be passed the
6379 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6383 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6384 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6385 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6389 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6413 parentLabelAlign : function()
6416 while (parent.parent()) {
6417 parent = parent.parent();
6418 if (typeof(parent.labelAlign) !='undefined') {
6419 return parent.labelAlign;
6426 getAutoCreate : function(){
6428 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6434 if(this.inputType != 'hidden'){
6435 cfg.cls = 'form-group' //input-group
6441 type : this.inputType,
6443 cls : 'form-control',
6444 placeholder : this.placeholder || ''
6449 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6452 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6453 input.maxLength = this.maxLength;
6456 if (this.disabled) {
6457 input.disabled=true;
6460 if (this.readOnly) {
6461 input.readonly=true;
6465 input.name = this.name;
6468 input.cls += ' input-' + this.size;
6471 ['xs','sm','md','lg'].map(function(size){
6472 if (settings[size]) {
6473 cfg.cls += ' col-' + size + '-' + settings[size];
6477 var inputblock = input;
6479 if (this.before || this.after) {
6482 cls : 'input-group',
6485 if (this.before && typeof(this.before) == 'string') {
6487 inputblock.cn.push({
6489 cls : 'roo-input-before input-group-addon',
6493 if (this.before && typeof(this.before) == 'object') {
6494 this.before = Roo.factory(this.before);
6495 Roo.log(this.before);
6496 inputblock.cn.push({
6498 cls : 'roo-input-before input-group-' +
6499 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6503 inputblock.cn.push(input);
6505 if (this.after && typeof(this.after) == 'string') {
6506 inputblock.cn.push({
6508 cls : 'roo-input-after input-group-addon',
6512 if (this.after && typeof(this.after) == 'object') {
6513 this.after = Roo.factory(this.after);
6514 Roo.log(this.after);
6515 inputblock.cn.push({
6517 cls : 'roo-input-after input-group-' +
6518 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6523 if (align ==='left' && this.fieldLabel.length) {
6524 Roo.log("left and has label");
6530 cls : 'control-label col-sm-' + this.labelWidth,
6531 html : this.fieldLabel
6535 cls : "col-sm-" + (12 - this.labelWidth),
6542 } else if ( this.fieldLabel.length) {
6548 //cls : 'input-group-addon',
6549 html : this.fieldLabel
6559 Roo.log(" no label && no align");
6568 Roo.log('input-parentType: ' + this.parentType);
6570 if (this.parentType === 'Navbar' && this.parent().bar) {
6571 cfg.cls += ' navbar-form';
6579 * return the real input element.
6581 inputEl: function ()
6583 return this.el.select('input.form-control',true).first();
6585 setDisabled : function(v)
6587 var i = this.inputEl().dom;
6589 i.removeAttribute('disabled');
6593 i.setAttribute('disabled','true');
6595 initEvents : function()
6598 this.inputEl().on("keydown" , this.fireKey, this);
6599 this.inputEl().on("focus", this.onFocus, this);
6600 this.inputEl().on("blur", this.onBlur, this);
6602 this.inputEl().relayEvent('keyup', this);
6604 // reference to original value for reset
6605 this.originalValue = this.getValue();
6606 //Roo.form.TextField.superclass.initEvents.call(this);
6607 if(this.validationEvent == 'keyup'){
6608 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6609 this.inputEl().on('keyup', this.filterValidation, this);
6611 else if(this.validationEvent !== false){
6612 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6615 if(this.selectOnFocus){
6616 this.on("focus", this.preFocus, this);
6619 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6620 this.inputEl().on("keypress", this.filterKeys, this);
6623 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6624 this.el.on("click", this.autoSize, this);
6627 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6628 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6631 if (typeof(this.before) == 'object') {
6632 this.before.render(this.el.select('.roo-input-before',true).first());
6634 if (typeof(this.after) == 'object') {
6635 this.after.render(this.el.select('.roo-input-after',true).first());
6640 filterValidation : function(e){
6641 if(!e.isNavKeyPress()){
6642 this.validationTask.delay(this.validationDelay);
6646 * Validates the field value
6647 * @return {Boolean} True if the value is valid, else false
6649 validate : function(){
6650 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6651 if(this.disabled || this.validateValue(this.getRawValue())){
6652 this.clearInvalid();
6660 * Validates a value according to the field's validation rules and marks the field as invalid
6661 * if the validation fails
6662 * @param {Mixed} value The value to validate
6663 * @return {Boolean} True if the value is valid, else false
6665 validateValue : function(value){
6666 if(value.length < 1) { // if it's blank
6667 if(this.allowBlank){
6668 this.clearInvalid();
6671 this.markInvalid(this.blankText);
6675 if(value.length < this.minLength){
6676 this.markInvalid(String.format(this.minLengthText, this.minLength));
6679 if(value.length > this.maxLength){
6680 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6684 var vt = Roo.form.VTypes;
6685 if(!vt[this.vtype](value, this)){
6686 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6690 if(typeof this.validator == "function"){
6691 var msg = this.validator(value);
6693 this.markInvalid(msg);
6697 if(this.regex && !this.regex.test(value)){
6698 this.markInvalid(this.regexText);
6707 fireKey : function(e){
6708 //Roo.log('field ' + e.getKey());
6709 if(e.isNavKeyPress()){
6710 this.fireEvent("specialkey", this, e);
6713 focus : function (selectText){
6715 this.inputEl().focus();
6716 if(selectText === true){
6717 this.inputEl().dom.select();
6723 onFocus : function(){
6724 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6725 // this.el.addClass(this.focusClass);
6728 this.hasFocus = true;
6729 this.startValue = this.getValue();
6730 this.fireEvent("focus", this);
6734 beforeBlur : Roo.emptyFn,
6738 onBlur : function(){
6740 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6741 //this.el.removeClass(this.focusClass);
6743 this.hasFocus = false;
6744 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6747 var v = this.getValue();
6748 if(String(v) !== String(this.startValue)){
6749 this.fireEvent('change', this, v, this.startValue);
6751 this.fireEvent("blur", this);
6755 * Resets the current field value to the originally loaded value and clears any validation messages
6758 this.setValue(this.originalValue);
6759 this.clearInvalid();
6762 * Returns the name of the field
6763 * @return {Mixed} name The name field
6765 getName: function(){
6769 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6770 * @return {Mixed} value The field value
6772 getValue : function(){
6773 return this.inputEl().getValue();
6776 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6777 * @return {Mixed} value The field value
6779 getRawValue : function(){
6780 var v = this.inputEl().getValue();
6786 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6787 * @param {Mixed} value The value to set
6789 setRawValue : function(v){
6790 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6793 selectText : function(start, end){
6794 var v = this.getRawValue();
6796 start = start === undefined ? 0 : start;
6797 end = end === undefined ? v.length : end;
6798 var d = this.inputEl().dom;
6799 if(d.setSelectionRange){
6800 d.setSelectionRange(start, end);
6801 }else if(d.createTextRange){
6802 var range = d.createTextRange();
6803 range.moveStart("character", start);
6804 range.moveEnd("character", v.length-end);
6811 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6812 * @param {Mixed} value The value to set
6814 setValue : function(v){
6817 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6823 processValue : function(value){
6824 if(this.stripCharsRe){
6825 var newValue = value.replace(this.stripCharsRe, '');
6826 if(newValue !== value){
6827 this.setRawValue(newValue);
6834 preFocus : function(){
6836 if(this.selectOnFocus){
6837 this.inputEl().dom.select();
6840 filterKeys : function(e){
6842 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6845 var c = e.getCharCode(), cc = String.fromCharCode(c);
6846 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6849 if(!this.maskRe.test(cc)){
6854 * Clear any invalid styles/messages for this field
6856 clearInvalid : function(){
6858 if(!this.el || this.preventMark){ // not rendered
6861 this.el.removeClass(this.invalidClass);
6863 switch(this.msgTarget){
6865 this.el.dom.qtip = '';
6868 this.el.dom.title = '';
6872 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6877 this.errorIcon.dom.qtip = '';
6878 this.errorIcon.hide();
6879 this.un('resize', this.alignErrorIcon, this);
6883 var t = Roo.getDom(this.msgTarget);
6885 t.style.display = 'none';
6889 this.fireEvent('valid', this);
6892 * Mark this field as invalid
6893 * @param {String} msg The validation message
6895 markInvalid : function(msg){
6896 if(!this.el || this.preventMark){ // not rendered
6899 this.el.addClass(this.invalidClass);
6901 msg = msg || this.invalidText;
6902 switch(this.msgTarget){
6904 this.el.dom.qtip = msg;
6905 this.el.dom.qclass = 'x-form-invalid-tip';
6906 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6907 Roo.QuickTips.enable();
6911 this.el.dom.title = msg;
6915 var elp = this.el.findParent('.x-form-element', 5, true);
6916 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6917 this.errorEl.setWidth(elp.getWidth(true)-20);
6919 this.errorEl.update(msg);
6920 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6923 if(!this.errorIcon){
6924 var elp = this.el.findParent('.x-form-element', 5, true);
6925 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6927 this.alignErrorIcon();
6928 this.errorIcon.dom.qtip = msg;
6929 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6930 this.errorIcon.show();
6931 this.on('resize', this.alignErrorIcon, this);
6934 var t = Roo.getDom(this.msgTarget);
6936 t.style.display = this.msgDisplay;
6940 this.fireEvent('invalid', this, msg);
6943 SafariOnKeyDown : function(event)
6945 // this is a workaround for a password hang bug on chrome/ webkit.
6947 var isSelectAll = false;
6949 if(this.inputEl().dom.selectionEnd > 0){
6950 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6952 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6953 event.preventDefault();
6958 if(isSelectAll){ // backspace and delete key
6960 event.preventDefault();
6961 // this is very hacky as keydown always get's upper case.
6963 var cc = String.fromCharCode(event.getCharCode());
6964 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6968 adjustWidth : function(tag, w){
6969 tag = tag.toLowerCase();
6970 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6971 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6975 if(tag == 'textarea'){
6978 }else if(Roo.isOpera){
6982 if(tag == 'textarea'){
7001 * @class Roo.bootstrap.TextArea
7002 * @extends Roo.bootstrap.Input
7003 * Bootstrap TextArea class
7004 * @cfg {Number} cols Specifies the visible width of a text area
7005 * @cfg {Number} rows Specifies the visible number of lines in a text area
7006 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7007 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7008 * @cfg {string} html text
7011 * Create a new TextArea
7012 * @param {Object} config The config object
7015 Roo.bootstrap.TextArea = function(config){
7016 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7020 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7030 getAutoCreate : function(){
7032 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7043 value : this.value || '',
7044 html: this.html || '',
7045 cls : 'form-control',
7046 placeholder : this.placeholder || ''
7050 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7051 input.maxLength = this.maxLength;
7055 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7059 input.cols = this.cols;
7062 if (this.readOnly) {
7063 input.readonly = true;
7067 input.name = this.name;
7071 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7075 ['xs','sm','md','lg'].map(function(size){
7076 if (settings[size]) {
7077 cfg.cls += ' col-' + size + '-' + settings[size];
7081 var inputblock = input;
7083 if (this.before || this.after) {
7086 cls : 'input-group',
7090 inputblock.cn.push({
7092 cls : 'input-group-addon',
7096 inputblock.cn.push(input);
7098 inputblock.cn.push({
7100 cls : 'input-group-addon',
7107 if (align ==='left' && this.fieldLabel.length) {
7108 Roo.log("left and has label");
7114 cls : 'control-label col-sm-' + this.labelWidth,
7115 html : this.fieldLabel
7119 cls : "col-sm-" + (12 - this.labelWidth),
7126 } else if ( this.fieldLabel.length) {
7132 //cls : 'input-group-addon',
7133 html : this.fieldLabel
7143 Roo.log(" no label && no align");
7153 if (this.disabled) {
7154 input.disabled=true;
7161 * return the real textarea element.
7163 inputEl: function ()
7165 return this.el.select('textarea.form-control',true).first();
7173 * trigger field - base class for combo..
7178 * @class Roo.bootstrap.TriggerField
7179 * @extends Roo.bootstrap.Input
7180 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7181 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7182 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7183 * for which you can provide a custom implementation. For example:
7185 var trigger = new Roo.bootstrap.TriggerField();
7186 trigger.onTriggerClick = myTriggerFn;
7187 trigger.applyTo('my-field');
7190 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7191 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7192 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7193 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7195 * Create a new TriggerField.
7196 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7197 * to the base TextField)
7199 Roo.bootstrap.TriggerField = function(config){
7200 this.mimicing = false;
7201 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7204 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7206 * @cfg {String} triggerClass A CSS class to apply to the trigger
7209 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7213 /** @cfg {Boolean} grow @hide */
7214 /** @cfg {Number} growMin @hide */
7215 /** @cfg {Number} growMax @hide */
7221 autoSize: Roo.emptyFn,
7228 actionMode : 'wrap',
7232 getAutoCreate : function(){
7234 var parent = this.parent();
7236 var align = this.labelAlign || this.parentLabelAlign();
7241 cls: 'form-group' //input-group
7248 type : this.inputType,
7249 cls : 'form-control',
7250 autocomplete: 'off',
7251 placeholder : this.placeholder || ''
7255 input.name = this.name;
7258 input.cls += ' input-' + this.size;
7261 if (this.disabled) {
7262 input.disabled=true;
7265 var inputblock = input;
7267 if (this.before || this.after) {
7270 cls : 'input-group',
7274 inputblock.cn.push({
7276 cls : 'input-group-addon',
7280 inputblock.cn.push(input);
7282 inputblock.cn.push({
7284 cls : 'input-group-addon',
7297 cls: 'form-hidden-field'
7305 Roo.log('multiple');
7313 cls: 'form-hidden-field'
7317 cls: 'select2-choices',
7321 cls: 'select2-search-field',
7334 cls: 'select2-container input-group',
7339 cls: 'typeahead typeahead-long dropdown-menu',
7340 style: 'display:none'
7348 cls : 'input-group-addon btn dropdown-toggle',
7356 cls: 'combobox-clear',
7370 combobox.cls += ' select2-container-multi';
7373 if (align ==='left' && this.fieldLabel.length) {
7375 Roo.log("left and has label");
7381 cls : 'control-label col-sm-' + this.labelWidth,
7382 html : this.fieldLabel
7386 cls : "col-sm-" + (12 - this.labelWidth),
7393 } else if ( this.fieldLabel.length) {
7399 //cls : 'input-group-addon',
7400 html : this.fieldLabel
7410 Roo.log(" no label && no align");
7417 ['xs','sm','md','lg'].map(function(size){
7418 if (settings[size]) {
7419 cfg.cls += ' col-' + size + '-' + settings[size];
7430 onResize : function(w, h){
7431 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7432 // if(typeof w == 'number'){
7433 // var x = w - this.trigger.getWidth();
7434 // this.inputEl().setWidth(this.adjustWidth('input', x));
7435 // this.trigger.setStyle('left', x+'px');
7440 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7443 getResizeEl : function(){
7444 return this.inputEl();
7448 getPositionEl : function(){
7449 return this.inputEl();
7453 alignErrorIcon : function(){
7454 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7458 initEvents : function(){
7460 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7461 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7463 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7464 if(this.hideTrigger){
7465 this.trigger.setDisplayed(false);
7467 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7471 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7474 //this.trigger.addClassOnOver('x-form-trigger-over');
7475 //this.trigger.addClassOnClick('x-form-trigger-click');
7478 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7483 initTrigger : function(){
7488 onDestroy : function(){
7490 this.trigger.removeAllListeners();
7491 // this.trigger.remove();
7494 // this.wrap.remove();
7496 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7500 onFocus : function(){
7501 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7504 this.wrap.addClass('x-trigger-wrap-focus');
7505 this.mimicing = true;
7506 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7507 if(this.monitorTab){
7508 this.el.on("keydown", this.checkTab, this);
7515 checkTab : function(e){
7516 if(e.getKey() == e.TAB){
7522 onBlur : function(){
7527 mimicBlur : function(e, t){
7529 if(!this.wrap.contains(t) && this.validateBlur()){
7536 triggerBlur : function(){
7537 this.mimicing = false;
7538 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7539 if(this.monitorTab){
7540 this.el.un("keydown", this.checkTab, this);
7542 //this.wrap.removeClass('x-trigger-wrap-focus');
7543 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7547 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7548 validateBlur : function(e, t){
7553 onDisable : function(){
7554 this.inputEl().dom.disabled = true;
7555 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7557 // this.wrap.addClass('x-item-disabled');
7562 onEnable : function(){
7563 this.inputEl().dom.disabled = false;
7564 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7566 // this.el.removeClass('x-item-disabled');
7571 onShow : function(){
7572 var ae = this.getActionEl();
7575 ae.dom.style.display = '';
7576 ae.dom.style.visibility = 'visible';
7582 onHide : function(){
7583 var ae = this.getActionEl();
7584 ae.dom.style.display = 'none';
7588 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7589 * by an implementing function.
7591 * @param {EventObject} e
7593 onTriggerClick : Roo.emptyFn
7597 * Ext JS Library 1.1.1
7598 * Copyright(c) 2006-2007, Ext JS, LLC.
7600 * Originally Released Under LGPL - original licence link has changed is not relivant.
7603 * <script type="text/javascript">
7608 * @class Roo.data.SortTypes
7610 * Defines the default sorting (casting?) comparison functions used when sorting data.
7612 Roo.data.SortTypes = {
7614 * Default sort that does nothing
7615 * @param {Mixed} s The value being converted
7616 * @return {Mixed} The comparison value
7623 * The regular expression used to strip tags
7627 stripTagsRE : /<\/?[^>]+>/gi,
7630 * Strips all HTML tags to sort on text only
7631 * @param {Mixed} s The value being converted
7632 * @return {String} The comparison value
7634 asText : function(s){
7635 return String(s).replace(this.stripTagsRE, "");
7639 * Strips all HTML tags to sort on text only - Case insensitive
7640 * @param {Mixed} s The value being converted
7641 * @return {String} The comparison value
7643 asUCText : function(s){
7644 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7648 * Case insensitive string
7649 * @param {Mixed} s The value being converted
7650 * @return {String} The comparison value
7652 asUCString : function(s) {
7653 return String(s).toUpperCase();
7658 * @param {Mixed} s The value being converted
7659 * @return {Number} The comparison value
7661 asDate : function(s) {
7665 if(s instanceof Date){
7668 return Date.parse(String(s));
7673 * @param {Mixed} s The value being converted
7674 * @return {Float} The comparison value
7676 asFloat : function(s) {
7677 var val = parseFloat(String(s).replace(/,/g, ""));
7678 if(isNaN(val)) val = 0;
7684 * @param {Mixed} s The value being converted
7685 * @return {Number} The comparison value
7687 asInt : function(s) {
7688 var val = parseInt(String(s).replace(/,/g, ""));
7689 if(isNaN(val)) val = 0;
7694 * Ext JS Library 1.1.1
7695 * Copyright(c) 2006-2007, Ext JS, LLC.
7697 * Originally Released Under LGPL - original licence link has changed is not relivant.
7700 * <script type="text/javascript">
7704 * @class Roo.data.Record
7705 * Instances of this class encapsulate both record <em>definition</em> information, and record
7706 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7707 * to access Records cached in an {@link Roo.data.Store} object.<br>
7709 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7710 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7713 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7715 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7716 * {@link #create}. The parameters are the same.
7717 * @param {Array} data An associative Array of data values keyed by the field name.
7718 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7719 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7720 * not specified an integer id is generated.
7722 Roo.data.Record = function(data, id){
7723 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7728 * Generate a constructor for a specific record layout.
7729 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7730 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7731 * Each field definition object may contain the following properties: <ul>
7732 * <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,
7733 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7734 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7735 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7736 * is being used, then this is a string containing the javascript expression to reference the data relative to
7737 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7738 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7739 * this may be omitted.</p></li>
7740 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7741 * <ul><li>auto (Default, implies no conversion)</li>
7746 * <li>date</li></ul></p></li>
7747 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7748 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7749 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7750 * by the Reader into an object that will be stored in the Record. It is passed the
7751 * following parameters:<ul>
7752 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7754 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7756 * <br>usage:<br><pre><code>
7757 var TopicRecord = Roo.data.Record.create(
7758 {name: 'title', mapping: 'topic_title'},
7759 {name: 'author', mapping: 'username'},
7760 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7761 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7762 {name: 'lastPoster', mapping: 'user2'},
7763 {name: 'excerpt', mapping: 'post_text'}
7766 var myNewRecord = new TopicRecord({
7767 title: 'Do my job please',
7770 lastPost: new Date(),
7771 lastPoster: 'Animal',
7772 excerpt: 'No way dude!'
7774 myStore.add(myNewRecord);
7779 Roo.data.Record.create = function(o){
7781 f.superclass.constructor.apply(this, arguments);
7783 Roo.extend(f, Roo.data.Record);
7784 var p = f.prototype;
7785 p.fields = new Roo.util.MixedCollection(false, function(field){
7788 for(var i = 0, len = o.length; i < len; i++){
7789 p.fields.add(new Roo.data.Field(o[i]));
7791 f.getField = function(name){
7792 return p.fields.get(name);
7797 Roo.data.Record.AUTO_ID = 1000;
7798 Roo.data.Record.EDIT = 'edit';
7799 Roo.data.Record.REJECT = 'reject';
7800 Roo.data.Record.COMMIT = 'commit';
7802 Roo.data.Record.prototype = {
7804 * Readonly flag - true if this record has been modified.
7813 join : function(store){
7818 * Set the named field to the specified value.
7819 * @param {String} name The name of the field to set.
7820 * @param {Object} value The value to set the field to.
7822 set : function(name, value){
7823 if(this.data[name] == value){
7830 if(typeof this.modified[name] == 'undefined'){
7831 this.modified[name] = this.data[name];
7833 this.data[name] = value;
7834 if(!this.editing && this.store){
7835 this.store.afterEdit(this);
7840 * Get the value of the named field.
7841 * @param {String} name The name of the field to get the value of.
7842 * @return {Object} The value of the field.
7844 get : function(name){
7845 return this.data[name];
7849 beginEdit : function(){
7850 this.editing = true;
7855 cancelEdit : function(){
7856 this.editing = false;
7857 delete this.modified;
7861 endEdit : function(){
7862 this.editing = false;
7863 if(this.dirty && this.store){
7864 this.store.afterEdit(this);
7869 * Usually called by the {@link Roo.data.Store} which owns the Record.
7870 * Rejects all changes made to the Record since either creation, or the last commit operation.
7871 * Modified fields are reverted to their original values.
7873 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7874 * of reject operations.
7876 reject : function(){
7877 var m = this.modified;
7879 if(typeof m[n] != "function"){
7880 this.data[n] = m[n];
7884 delete this.modified;
7885 this.editing = false;
7887 this.store.afterReject(this);
7892 * Usually called by the {@link Roo.data.Store} which owns the Record.
7893 * Commits all changes made to the Record since either creation, or the last commit operation.
7895 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7896 * of commit operations.
7898 commit : function(){
7900 delete this.modified;
7901 this.editing = false;
7903 this.store.afterCommit(this);
7908 hasError : function(){
7909 return this.error != null;
7913 clearError : function(){
7918 * Creates a copy of this record.
7919 * @param {String} id (optional) A new record id if you don't want to use this record's id
7922 copy : function(newId) {
7923 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7927 * Ext JS Library 1.1.1
7928 * Copyright(c) 2006-2007, Ext JS, LLC.
7930 * Originally Released Under LGPL - original licence link has changed is not relivant.
7933 * <script type="text/javascript">
7939 * @class Roo.data.Store
7940 * @extends Roo.util.Observable
7941 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7942 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7944 * 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
7945 * has no knowledge of the format of the data returned by the Proxy.<br>
7947 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7948 * instances from the data object. These records are cached and made available through accessor functions.
7950 * Creates a new Store.
7951 * @param {Object} config A config object containing the objects needed for the Store to access data,
7952 * and read the data into Records.
7954 Roo.data.Store = function(config){
7955 this.data = new Roo.util.MixedCollection(false);
7956 this.data.getKey = function(o){
7959 this.baseParams = {};
7966 "multisort" : "_multisort"
7969 if(config && config.data){
7970 this.inlineData = config.data;
7974 Roo.apply(this, config);
7976 if(this.reader){ // reader passed
7977 this.reader = Roo.factory(this.reader, Roo.data);
7978 this.reader.xmodule = this.xmodule || false;
7979 if(!this.recordType){
7980 this.recordType = this.reader.recordType;
7982 if(this.reader.onMetaChange){
7983 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7987 if(this.recordType){
7988 this.fields = this.recordType.prototype.fields;
7994 * @event datachanged
7995 * Fires when the data cache has changed, and a widget which is using this Store
7996 * as a Record cache should refresh its view.
7997 * @param {Store} this
8002 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8003 * @param {Store} this
8004 * @param {Object} meta The JSON metadata
8009 * Fires when Records have been added to the Store
8010 * @param {Store} this
8011 * @param {Roo.data.Record[]} records The array of Records added
8012 * @param {Number} index The index at which the record(s) were added
8017 * Fires when a Record has been removed from the Store
8018 * @param {Store} this
8019 * @param {Roo.data.Record} record The Record that was removed
8020 * @param {Number} index The index at which the record was removed
8025 * Fires when a Record has been updated
8026 * @param {Store} this
8027 * @param {Roo.data.Record} record The Record that was updated
8028 * @param {String} operation The update operation being performed. Value may be one of:
8030 Roo.data.Record.EDIT
8031 Roo.data.Record.REJECT
8032 Roo.data.Record.COMMIT
8038 * Fires when the data cache has been cleared.
8039 * @param {Store} this
8044 * Fires before a request is made for a new data object. If the beforeload handler returns false
8045 * the load action will be canceled.
8046 * @param {Store} this
8047 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8051 * @event beforeloadadd
8052 * Fires after a new set of Records has been loaded.
8053 * @param {Store} this
8054 * @param {Roo.data.Record[]} records The Records that were loaded
8055 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8057 beforeloadadd : true,
8060 * Fires after a new set of Records has been loaded, before they are added to the store.
8061 * @param {Store} this
8062 * @param {Roo.data.Record[]} records The Records that were loaded
8063 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8064 * @params {Object} return from reader
8068 * @event loadexception
8069 * Fires if an exception occurs in the Proxy during loading.
8070 * Called with the signature of the Proxy's "loadexception" event.
8071 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8074 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8075 * @param {Object} load options
8076 * @param {Object} jsonData from your request (normally this contains the Exception)
8078 loadexception : true
8082 this.proxy = Roo.factory(this.proxy, Roo.data);
8083 this.proxy.xmodule = this.xmodule || false;
8084 this.relayEvents(this.proxy, ["loadexception"]);
8086 this.sortToggle = {};
8087 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8089 Roo.data.Store.superclass.constructor.call(this);
8091 if(this.inlineData){
8092 this.loadData(this.inlineData);
8093 delete this.inlineData;
8097 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8099 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8100 * without a remote query - used by combo/forms at present.
8104 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8107 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8110 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8111 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8114 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8115 * on any HTTP request
8118 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8121 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8125 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8126 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8131 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8132 * loaded or when a record is removed. (defaults to false).
8134 pruneModifiedRecords : false,
8140 * Add Records to the Store and fires the add event.
8141 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8143 add : function(records){
8144 records = [].concat(records);
8145 for(var i = 0, len = records.length; i < len; i++){
8146 records[i].join(this);
8148 var index = this.data.length;
8149 this.data.addAll(records);
8150 this.fireEvent("add", this, records, index);
8154 * Remove a Record from the Store and fires the remove event.
8155 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8157 remove : function(record){
8158 var index = this.data.indexOf(record);
8159 this.data.removeAt(index);
8160 if(this.pruneModifiedRecords){
8161 this.modified.remove(record);
8163 this.fireEvent("remove", this, record, index);
8167 * Remove all Records from the Store and fires the clear event.
8169 removeAll : function(){
8171 if(this.pruneModifiedRecords){
8174 this.fireEvent("clear", this);
8178 * Inserts Records to the Store at the given index and fires the add event.
8179 * @param {Number} index The start index at which to insert the passed Records.
8180 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8182 insert : function(index, records){
8183 records = [].concat(records);
8184 for(var i = 0, len = records.length; i < len; i++){
8185 this.data.insert(index, records[i]);
8186 records[i].join(this);
8188 this.fireEvent("add", this, records, index);
8192 * Get the index within the cache of the passed Record.
8193 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8194 * @return {Number} The index of the passed Record. Returns -1 if not found.
8196 indexOf : function(record){
8197 return this.data.indexOf(record);
8201 * Get the index within the cache of the Record with the passed id.
8202 * @param {String} id The id of the Record to find.
8203 * @return {Number} The index of the Record. Returns -1 if not found.
8205 indexOfId : function(id){
8206 return this.data.indexOfKey(id);
8210 * Get the Record with the specified id.
8211 * @param {String} id The id of the Record to find.
8212 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8214 getById : function(id){
8215 return this.data.key(id);
8219 * Get the Record at the specified index.
8220 * @param {Number} index The index of the Record to find.
8221 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8223 getAt : function(index){
8224 return this.data.itemAt(index);
8228 * Returns a range of Records between specified indices.
8229 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8230 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8231 * @return {Roo.data.Record[]} An array of Records
8233 getRange : function(start, end){
8234 return this.data.getRange(start, end);
8238 storeOptions : function(o){
8239 o = Roo.apply({}, o);
8242 this.lastOptions = o;
8246 * Loads the Record cache from the configured Proxy using the configured Reader.
8248 * If using remote paging, then the first load call must specify the <em>start</em>
8249 * and <em>limit</em> properties in the options.params property to establish the initial
8250 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8252 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8253 * and this call will return before the new data has been loaded. Perform any post-processing
8254 * in a callback function, or in a "load" event handler.</strong>
8256 * @param {Object} options An object containing properties which control loading options:<ul>
8257 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8258 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8259 * passed the following arguments:<ul>
8260 * <li>r : Roo.data.Record[]</li>
8261 * <li>options: Options object from the load call</li>
8262 * <li>success: Boolean success indicator</li></ul></li>
8263 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8264 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8267 load : function(options){
8268 options = options || {};
8269 if(this.fireEvent("beforeload", this, options) !== false){
8270 this.storeOptions(options);
8271 var p = Roo.apply(options.params || {}, this.baseParams);
8272 // if meta was not loaded from remote source.. try requesting it.
8273 if (!this.reader.metaFromRemote) {
8276 if(this.sortInfo && this.remoteSort){
8277 var pn = this.paramNames;
8278 p[pn["sort"]] = this.sortInfo.field;
8279 p[pn["dir"]] = this.sortInfo.direction;
8281 if (this.multiSort) {
8282 var pn = this.paramNames;
8283 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8286 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8291 * Reloads the Record cache from the configured Proxy using the configured Reader and
8292 * the options from the last load operation performed.
8293 * @param {Object} options (optional) An object containing properties which may override the options
8294 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8295 * the most recently used options are reused).
8297 reload : function(options){
8298 this.load(Roo.applyIf(options||{}, this.lastOptions));
8302 // Called as a callback by the Reader during a load operation.
8303 loadRecords : function(o, options, success){
8304 if(!o || success === false){
8305 if(success !== false){
8306 this.fireEvent("load", this, [], options, o);
8308 if(options.callback){
8309 options.callback.call(options.scope || this, [], options, false);
8313 // if data returned failure - throw an exception.
8314 if (o.success === false) {
8315 // show a message if no listener is registered.
8316 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8317 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8319 // loadmask wil be hooked into this..
8320 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8323 var r = o.records, t = o.totalRecords || r.length;
8325 this.fireEvent("beforeloadadd", this, r, options, o);
8327 if(!options || options.add !== true){
8328 if(this.pruneModifiedRecords){
8331 for(var i = 0, len = r.length; i < len; i++){
8335 this.data = this.snapshot;
8336 delete this.snapshot;
8339 this.data.addAll(r);
8340 this.totalLength = t;
8342 this.fireEvent("datachanged", this);
8344 this.totalLength = Math.max(t, this.data.length+r.length);
8347 this.fireEvent("load", this, r, options, o);
8348 if(options.callback){
8349 options.callback.call(options.scope || this, r, options, true);
8355 * Loads data from a passed data block. A Reader which understands the format of the data
8356 * must have been configured in the constructor.
8357 * @param {Object} data The data block from which to read the Records. The format of the data expected
8358 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8359 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8361 loadData : function(o, append){
8362 var r = this.reader.readRecords(o);
8363 this.loadRecords(r, {add: append}, true);
8367 * Gets the number of cached records.
8369 * <em>If using paging, this may not be the total size of the dataset. If the data object
8370 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8371 * the data set size</em>
8373 getCount : function(){
8374 return this.data.length || 0;
8378 * Gets the total number of records in the dataset as returned by the server.
8380 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8381 * the dataset size</em>
8383 getTotalCount : function(){
8384 return this.totalLength || 0;
8388 * Returns the sort state of the Store as an object with two properties:
8390 field {String} The name of the field by which the Records are sorted
8391 direction {String} The sort order, "ASC" or "DESC"
8394 getSortState : function(){
8395 return this.sortInfo;
8399 applySort : function(){
8400 if(this.sortInfo && !this.remoteSort){
8401 var s = this.sortInfo, f = s.field;
8402 var st = this.fields.get(f).sortType;
8403 var fn = function(r1, r2){
8404 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8405 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8407 this.data.sort(s.direction, fn);
8408 if(this.snapshot && this.snapshot != this.data){
8409 this.snapshot.sort(s.direction, fn);
8415 * Sets the default sort column and order to be used by the next load operation.
8416 * @param {String} fieldName The name of the field to sort by.
8417 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8419 setDefaultSort : function(field, dir){
8420 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8425 * If remote sorting is used, the sort is performed on the server, and the cache is
8426 * reloaded. If local sorting is used, the cache is sorted internally.
8427 * @param {String} fieldName The name of the field to sort by.
8428 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8430 sort : function(fieldName, dir){
8431 var f = this.fields.get(fieldName);
8433 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8435 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8436 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8441 this.sortToggle[f.name] = dir;
8442 this.sortInfo = {field: f.name, direction: dir};
8443 if(!this.remoteSort){
8445 this.fireEvent("datachanged", this);
8447 this.load(this.lastOptions);
8452 * Calls the specified function for each of the Records in the cache.
8453 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8454 * Returning <em>false</em> aborts and exits the iteration.
8455 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8457 each : function(fn, scope){
8458 this.data.each(fn, scope);
8462 * Gets all records modified since the last commit. Modified records are persisted across load operations
8463 * (e.g., during paging).
8464 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8466 getModifiedRecords : function(){
8467 return this.modified;
8471 createFilterFn : function(property, value, anyMatch){
8472 if(!value.exec){ // not a regex
8473 value = String(value);
8474 if(value.length == 0){
8477 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8480 return value.test(r.data[property]);
8485 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8486 * @param {String} property A field on your records
8487 * @param {Number} start The record index to start at (defaults to 0)
8488 * @param {Number} end The last record index to include (defaults to length - 1)
8489 * @return {Number} The sum
8491 sum : function(property, start, end){
8492 var rs = this.data.items, v = 0;
8494 end = (end || end === 0) ? end : rs.length-1;
8496 for(var i = start; i <= end; i++){
8497 v += (rs[i].data[property] || 0);
8503 * Filter the records by a specified property.
8504 * @param {String} field A field on your records
8505 * @param {String/RegExp} value Either a string that the field
8506 * should start with or a RegExp to test against the field
8507 * @param {Boolean} anyMatch True to match any part not just the beginning
8509 filter : function(property, value, anyMatch){
8510 var fn = this.createFilterFn(property, value, anyMatch);
8511 return fn ? this.filterBy(fn) : this.clearFilter();
8515 * Filter by a function. The specified function will be called with each
8516 * record in this data source. If the function returns true the record is included,
8517 * otherwise it is filtered.
8518 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8519 * @param {Object} scope (optional) The scope of the function (defaults to this)
8521 filterBy : function(fn, scope){
8522 this.snapshot = this.snapshot || this.data;
8523 this.data = this.queryBy(fn, scope||this);
8524 this.fireEvent("datachanged", this);
8528 * Query the records by a specified property.
8529 * @param {String} field A field on your records
8530 * @param {String/RegExp} value Either a string that the field
8531 * should start with or a RegExp to test against the field
8532 * @param {Boolean} anyMatch True to match any part not just the beginning
8533 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8535 query : function(property, value, anyMatch){
8536 var fn = this.createFilterFn(property, value, anyMatch);
8537 return fn ? this.queryBy(fn) : this.data.clone();
8541 * Query by a function. The specified function will be called with each
8542 * record in this data source. If the function returns true the record is included
8544 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8545 * @param {Object} scope (optional) The scope of the function (defaults to this)
8546 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8548 queryBy : function(fn, scope){
8549 var data = this.snapshot || this.data;
8550 return data.filterBy(fn, scope||this);
8554 * Collects unique values for a particular dataIndex from this store.
8555 * @param {String} dataIndex The property to collect
8556 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8557 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8558 * @return {Array} An array of the unique values
8560 collect : function(dataIndex, allowNull, bypassFilter){
8561 var d = (bypassFilter === true && this.snapshot) ?
8562 this.snapshot.items : this.data.items;
8563 var v, sv, r = [], l = {};
8564 for(var i = 0, len = d.length; i < len; i++){
8565 v = d[i].data[dataIndex];
8567 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8576 * Revert to a view of the Record cache with no filtering applied.
8577 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8579 clearFilter : function(suppressEvent){
8580 if(this.snapshot && this.snapshot != this.data){
8581 this.data = this.snapshot;
8582 delete this.snapshot;
8583 if(suppressEvent !== true){
8584 this.fireEvent("datachanged", this);
8590 afterEdit : function(record){
8591 if(this.modified.indexOf(record) == -1){
8592 this.modified.push(record);
8594 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8598 afterReject : function(record){
8599 this.modified.remove(record);
8600 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8604 afterCommit : function(record){
8605 this.modified.remove(record);
8606 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8610 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8611 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8613 commitChanges : function(){
8614 var m = this.modified.slice(0);
8616 for(var i = 0, len = m.length; i < len; i++){
8622 * Cancel outstanding changes on all changed records.
8624 rejectChanges : function(){
8625 var m = this.modified.slice(0);
8627 for(var i = 0, len = m.length; i < len; i++){
8632 onMetaChange : function(meta, rtype, o){
8633 this.recordType = rtype;
8634 this.fields = rtype.prototype.fields;
8635 delete this.snapshot;
8636 this.sortInfo = meta.sortInfo || this.sortInfo;
8638 this.fireEvent('metachange', this, this.reader.meta);
8641 moveIndex : function(data, type)
8643 var index = this.indexOf(data);
8645 var newIndex = index + type;
8649 this.insert(newIndex, data);
8654 * Ext JS Library 1.1.1
8655 * Copyright(c) 2006-2007, Ext JS, LLC.
8657 * Originally Released Under LGPL - original licence link has changed is not relivant.
8660 * <script type="text/javascript">
8664 * @class Roo.data.SimpleStore
8665 * @extends Roo.data.Store
8666 * Small helper class to make creating Stores from Array data easier.
8667 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8668 * @cfg {Array} fields An array of field definition objects, or field name strings.
8669 * @cfg {Array} data The multi-dimensional array of data
8671 * @param {Object} config
8673 Roo.data.SimpleStore = function(config){
8674 Roo.data.SimpleStore.superclass.constructor.call(this, {
8676 reader: new Roo.data.ArrayReader({
8679 Roo.data.Record.create(config.fields)
8681 proxy : new Roo.data.MemoryProxy(config.data)
8685 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8687 * Ext JS Library 1.1.1
8688 * Copyright(c) 2006-2007, Ext JS, LLC.
8690 * Originally Released Under LGPL - original licence link has changed is not relivant.
8693 * <script type="text/javascript">
8698 * @extends Roo.data.Store
8699 * @class Roo.data.JsonStore
8700 * Small helper class to make creating Stores for JSON data easier. <br/>
8702 var store = new Roo.data.JsonStore({
8703 url: 'get-images.php',
8705 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8708 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8709 * JsonReader and HttpProxy (unless inline data is provided).</b>
8710 * @cfg {Array} fields An array of field definition objects, or field name strings.
8712 * @param {Object} config
8714 Roo.data.JsonStore = function(c){
8715 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8716 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8717 reader: new Roo.data.JsonReader(c, c.fields)
8720 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8722 * Ext JS Library 1.1.1
8723 * Copyright(c) 2006-2007, Ext JS, LLC.
8725 * Originally Released Under LGPL - original licence link has changed is not relivant.
8728 * <script type="text/javascript">
8732 Roo.data.Field = function(config){
8733 if(typeof config == "string"){
8734 config = {name: config};
8736 Roo.apply(this, config);
8742 var st = Roo.data.SortTypes;
8743 // named sortTypes are supported, here we look them up
8744 if(typeof this.sortType == "string"){
8745 this.sortType = st[this.sortType];
8748 // set default sortType for strings and dates
8752 this.sortType = st.asUCString;
8755 this.sortType = st.asDate;
8758 this.sortType = st.none;
8763 var stripRe = /[\$,%]/g;
8765 // prebuilt conversion function for this field, instead of
8766 // switching every time we're reading a value
8768 var cv, dateFormat = this.dateFormat;
8773 cv = function(v){ return v; };
8776 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8780 return v !== undefined && v !== null && v !== '' ?
8781 parseInt(String(v).replace(stripRe, ""), 10) : '';
8786 return v !== undefined && v !== null && v !== '' ?
8787 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8792 cv = function(v){ return v === true || v === "true" || v == 1; };
8799 if(v instanceof Date){
8803 if(dateFormat == "timestamp"){
8804 return new Date(v*1000);
8806 return Date.parseDate(v, dateFormat);
8808 var parsed = Date.parse(v);
8809 return parsed ? new Date(parsed) : null;
8818 Roo.data.Field.prototype = {
8826 * Ext JS Library 1.1.1
8827 * Copyright(c) 2006-2007, Ext JS, LLC.
8829 * Originally Released Under LGPL - original licence link has changed is not relivant.
8832 * <script type="text/javascript">
8835 // Base class for reading structured data from a data source. This class is intended to be
8836 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8839 * @class Roo.data.DataReader
8840 * Base class for reading structured data from a data source. This class is intended to be
8841 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8844 Roo.data.DataReader = function(meta, recordType){
8848 this.recordType = recordType instanceof Array ?
8849 Roo.data.Record.create(recordType) : recordType;
8852 Roo.data.DataReader.prototype = {
8854 * Create an empty record
8855 * @param {Object} data (optional) - overlay some values
8856 * @return {Roo.data.Record} record created.
8858 newRow : function(d) {
8860 this.recordType.prototype.fields.each(function(c) {
8862 case 'int' : da[c.name] = 0; break;
8863 case 'date' : da[c.name] = new Date(); break;
8864 case 'float' : da[c.name] = 0.0; break;
8865 case 'boolean' : da[c.name] = false; break;
8866 default : da[c.name] = ""; break;
8870 return new this.recordType(Roo.apply(da, d));
8875 * Ext JS Library 1.1.1
8876 * Copyright(c) 2006-2007, Ext JS, LLC.
8878 * Originally Released Under LGPL - original licence link has changed is not relivant.
8881 * <script type="text/javascript">
8885 * @class Roo.data.DataProxy
8886 * @extends Roo.data.Observable
8887 * This class is an abstract base class for implementations which provide retrieval of
8888 * unformatted data objects.<br>
8890 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8891 * (of the appropriate type which knows how to parse the data object) to provide a block of
8892 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8894 * Custom implementations must implement the load method as described in
8895 * {@link Roo.data.HttpProxy#load}.
8897 Roo.data.DataProxy = function(){
8901 * Fires before a network request is made to retrieve a data object.
8902 * @param {Object} This DataProxy object.
8903 * @param {Object} params The params parameter to the load function.
8908 * Fires before the load method's callback is called.
8909 * @param {Object} This DataProxy object.
8910 * @param {Object} o The data object.
8911 * @param {Object} arg The callback argument object passed to the load function.
8915 * @event loadexception
8916 * Fires if an Exception occurs during data retrieval.
8917 * @param {Object} This DataProxy object.
8918 * @param {Object} o The data object.
8919 * @param {Object} arg The callback argument object passed to the load function.
8920 * @param {Object} e The Exception.
8922 loadexception : true
8924 Roo.data.DataProxy.superclass.constructor.call(this);
8927 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8930 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8934 * Ext JS Library 1.1.1
8935 * Copyright(c) 2006-2007, Ext JS, LLC.
8937 * Originally Released Under LGPL - original licence link has changed is not relivant.
8940 * <script type="text/javascript">
8943 * @class Roo.data.MemoryProxy
8944 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8945 * to the Reader when its load method is called.
8947 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8949 Roo.data.MemoryProxy = function(data){
8953 Roo.data.MemoryProxy.superclass.constructor.call(this);
8957 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8959 * Load data from the requested source (in this case an in-memory
8960 * data object passed to the constructor), read the data object into
8961 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8962 * process that block using the passed callback.
8963 * @param {Object} params This parameter is not used by the MemoryProxy class.
8964 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8965 * object into a block of Roo.data.Records.
8966 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8967 * The function must be passed <ul>
8968 * <li>The Record block object</li>
8969 * <li>The "arg" argument from the load function</li>
8970 * <li>A boolean success indicator</li>
8972 * @param {Object} scope The scope in which to call the callback
8973 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8975 load : function(params, reader, callback, scope, arg){
8976 params = params || {};
8979 result = reader.readRecords(this.data);
8981 this.fireEvent("loadexception", this, arg, null, e);
8982 callback.call(scope, null, arg, false);
8985 callback.call(scope, result, arg, true);
8989 update : function(params, records){
8994 * Ext JS Library 1.1.1
8995 * Copyright(c) 2006-2007, Ext JS, LLC.
8997 * Originally Released Under LGPL - original licence link has changed is not relivant.
9000 * <script type="text/javascript">
9003 * @class Roo.data.HttpProxy
9004 * @extends Roo.data.DataProxy
9005 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9006 * configured to reference a certain URL.<br><br>
9008 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9009 * from which the running page was served.<br><br>
9011 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9013 * Be aware that to enable the browser to parse an XML document, the server must set
9014 * the Content-Type header in the HTTP response to "text/xml".
9016 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9017 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9018 * will be used to make the request.
9020 Roo.data.HttpProxy = function(conn){
9021 Roo.data.HttpProxy.superclass.constructor.call(this);
9022 // is conn a conn config or a real conn?
9024 this.useAjax = !conn || !conn.events;
9028 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9029 // thse are take from connection...
9032 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9035 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9036 * extra parameters to each request made by this object. (defaults to undefined)
9039 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9040 * to each request made by this object. (defaults to undefined)
9043 * @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)
9046 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9049 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9055 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9059 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9060 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9061 * a finer-grained basis than the DataProxy events.
9063 getConnection : function(){
9064 return this.useAjax ? Roo.Ajax : this.conn;
9068 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9069 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9070 * process that block using the passed callback.
9071 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9072 * for the request to the remote server.
9073 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9074 * object into a block of Roo.data.Records.
9075 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9076 * The function must be passed <ul>
9077 * <li>The Record block object</li>
9078 * <li>The "arg" argument from the load function</li>
9079 * <li>A boolean success indicator</li>
9081 * @param {Object} scope The scope in which to call the callback
9082 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9084 load : function(params, reader, callback, scope, arg){
9085 if(this.fireEvent("beforeload", this, params) !== false){
9087 params : params || {},
9089 callback : callback,
9094 callback : this.loadResponse,
9098 Roo.applyIf(o, this.conn);
9099 if(this.activeRequest){
9100 Roo.Ajax.abort(this.activeRequest);
9102 this.activeRequest = Roo.Ajax.request(o);
9104 this.conn.request(o);
9107 callback.call(scope||this, null, arg, false);
9112 loadResponse : function(o, success, response){
9113 delete this.activeRequest;
9115 this.fireEvent("loadexception", this, o, response);
9116 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9121 result = o.reader.read(response);
9123 this.fireEvent("loadexception", this, o, response, e);
9124 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9128 this.fireEvent("load", this, o, o.request.arg);
9129 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9133 update : function(dataSet){
9138 updateResponse : function(dataSet){
9143 * Ext JS Library 1.1.1
9144 * Copyright(c) 2006-2007, Ext JS, LLC.
9146 * Originally Released Under LGPL - original licence link has changed is not relivant.
9149 * <script type="text/javascript">
9153 * @class Roo.data.ScriptTagProxy
9154 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9155 * other than the originating domain of the running page.<br><br>
9157 * <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
9158 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9160 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9161 * source code that is used as the source inside a <script> tag.<br><br>
9163 * In order for the browser to process the returned data, the server must wrap the data object
9164 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9165 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9166 * depending on whether the callback name was passed:
9169 boolean scriptTag = false;
9170 String cb = request.getParameter("callback");
9173 response.setContentType("text/javascript");
9175 response.setContentType("application/x-json");
9177 Writer out = response.getWriter();
9179 out.write(cb + "(");
9181 out.print(dataBlock.toJsonString());
9188 * @param {Object} config A configuration object.
9190 Roo.data.ScriptTagProxy = function(config){
9191 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9192 Roo.apply(this, config);
9193 this.head = document.getElementsByTagName("head")[0];
9196 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9198 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9200 * @cfg {String} url The URL from which to request the data object.
9203 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9207 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9208 * the server the name of the callback function set up by the load call to process the returned data object.
9209 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9210 * javascript output which calls this named function passing the data object as its only parameter.
9212 callbackParam : "callback",
9214 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9215 * name to the request.
9220 * Load data from the configured URL, read the data object into
9221 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9222 * process that block using the passed callback.
9223 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9224 * for the request to the remote server.
9225 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9226 * object into a block of Roo.data.Records.
9227 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9228 * The function must be passed <ul>
9229 * <li>The Record block object</li>
9230 * <li>The "arg" argument from the load function</li>
9231 * <li>A boolean success indicator</li>
9233 * @param {Object} scope The scope in which to call the callback
9234 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9236 load : function(params, reader, callback, scope, arg){
9237 if(this.fireEvent("beforeload", this, params) !== false){
9239 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9242 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9244 url += "&_dc=" + (new Date().getTime());
9246 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9249 cb : "stcCallback"+transId,
9250 scriptId : "stcScript"+transId,
9254 callback : callback,
9260 window[trans.cb] = function(o){
9261 conn.handleResponse(o, trans);
9264 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9266 if(this.autoAbort !== false){
9270 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9272 var script = document.createElement("script");
9273 script.setAttribute("src", url);
9274 script.setAttribute("type", "text/javascript");
9275 script.setAttribute("id", trans.scriptId);
9276 this.head.appendChild(script);
9280 callback.call(scope||this, null, arg, false);
9285 isLoading : function(){
9286 return this.trans ? true : false;
9290 * Abort the current server request.
9293 if(this.isLoading()){
9294 this.destroyTrans(this.trans);
9299 destroyTrans : function(trans, isLoaded){
9300 this.head.removeChild(document.getElementById(trans.scriptId));
9301 clearTimeout(trans.timeoutId);
9303 window[trans.cb] = undefined;
9305 delete window[trans.cb];
9308 // if hasn't been loaded, wait for load to remove it to prevent script error
9309 window[trans.cb] = function(){
9310 window[trans.cb] = undefined;
9312 delete window[trans.cb];
9319 handleResponse : function(o, trans){
9321 this.destroyTrans(trans, true);
9324 result = trans.reader.readRecords(o);
9326 this.fireEvent("loadexception", this, o, trans.arg, e);
9327 trans.callback.call(trans.scope||window, null, trans.arg, false);
9330 this.fireEvent("load", this, o, trans.arg);
9331 trans.callback.call(trans.scope||window, result, trans.arg, true);
9335 handleFailure : function(trans){
9337 this.destroyTrans(trans, false);
9338 this.fireEvent("loadexception", this, null, trans.arg);
9339 trans.callback.call(trans.scope||window, null, trans.arg, false);
9343 * Ext JS Library 1.1.1
9344 * Copyright(c) 2006-2007, Ext JS, LLC.
9346 * Originally Released Under LGPL - original licence link has changed is not relivant.
9349 * <script type="text/javascript">
9353 * @class Roo.data.JsonReader
9354 * @extends Roo.data.DataReader
9355 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9356 * based on mappings in a provided Roo.data.Record constructor.
9358 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9359 * in the reply previously.
9364 var RecordDef = Roo.data.Record.create([
9365 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9366 {name: 'occupation'} // This field will use "occupation" as the mapping.
9368 var myReader = new Roo.data.JsonReader({
9369 totalProperty: "results", // The property which contains the total dataset size (optional)
9370 root: "rows", // The property which contains an Array of row objects
9371 id: "id" // The property within each row object that provides an ID for the record (optional)
9375 * This would consume a JSON file like this:
9377 { 'results': 2, 'rows': [
9378 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9379 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9382 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9383 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9384 * paged from the remote server.
9385 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9386 * @cfg {String} root name of the property which contains the Array of row objects.
9387 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9389 * Create a new JsonReader
9390 * @param {Object} meta Metadata configuration options
9391 * @param {Object} recordType Either an Array of field definition objects,
9392 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9394 Roo.data.JsonReader = function(meta, recordType){
9397 // set some defaults:
9399 totalProperty: 'total',
9400 successProperty : 'success',
9405 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9407 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9410 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9411 * Used by Store query builder to append _requestMeta to params.
9414 metaFromRemote : false,
9416 * This method is only used by a DataProxy which has retrieved data from a remote server.
9417 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9418 * @return {Object} data A data block which is used by an Roo.data.Store object as
9419 * a cache of Roo.data.Records.
9421 read : function(response){
9422 var json = response.responseText;
9424 var o = /* eval:var:o */ eval("("+json+")");
9426 throw {message: "JsonReader.read: Json object not found"};
9432 this.metaFromRemote = true;
9433 this.meta = o.metaData;
9434 this.recordType = Roo.data.Record.create(o.metaData.fields);
9435 this.onMetaChange(this.meta, this.recordType, o);
9437 return this.readRecords(o);
9440 // private function a store will implement
9441 onMetaChange : function(meta, recordType, o){
9448 simpleAccess: function(obj, subsc) {
9455 getJsonAccessor: function(){
9457 return function(expr) {
9459 return(re.test(expr))
9460 ? new Function("obj", "return obj." + expr)
9470 * Create a data block containing Roo.data.Records from an XML document.
9471 * @param {Object} o An object which contains an Array of row objects in the property specified
9472 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9473 * which contains the total size of the dataset.
9474 * @return {Object} data A data block which is used by an Roo.data.Store object as
9475 * a cache of Roo.data.Records.
9477 readRecords : function(o){
9479 * After any data loads, the raw JSON data is available for further custom processing.
9483 var s = this.meta, Record = this.recordType,
9484 f = Record.prototype.fields, fi = f.items, fl = f.length;
9486 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9488 if(s.totalProperty) {
9489 this.getTotal = this.getJsonAccessor(s.totalProperty);
9491 if(s.successProperty) {
9492 this.getSuccess = this.getJsonAccessor(s.successProperty);
9494 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9496 var g = this.getJsonAccessor(s.id);
9497 this.getId = function(rec) {
9499 return (r === undefined || r === "") ? null : r;
9502 this.getId = function(){return null;};
9505 for(var jj = 0; jj < fl; jj++){
9507 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9508 this.ef[jj] = this.getJsonAccessor(map);
9512 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9513 if(s.totalProperty){
9514 var vt = parseInt(this.getTotal(o), 10);
9519 if(s.successProperty){
9520 var vs = this.getSuccess(o);
9521 if(vs === false || vs === 'false'){
9526 for(var i = 0; i < c; i++){
9529 var id = this.getId(n);
9530 for(var j = 0; j < fl; j++){
9532 var v = this.ef[j](n);
9534 Roo.log('missing convert for ' + f.name);
9538 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9540 var record = new Record(values, id);
9542 records[i] = record;
9548 totalRecords : totalRecords
9553 * Ext JS Library 1.1.1
9554 * Copyright(c) 2006-2007, Ext JS, LLC.
9556 * Originally Released Under LGPL - original licence link has changed is not relivant.
9559 * <script type="text/javascript">
9563 * @class Roo.data.ArrayReader
9564 * @extends Roo.data.DataReader
9565 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9566 * Each element of that Array represents a row of data fields. The
9567 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9568 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9572 var RecordDef = Roo.data.Record.create([
9573 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9574 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9576 var myReader = new Roo.data.ArrayReader({
9577 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9581 * This would consume an Array like this:
9583 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9585 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9587 * Create a new JsonReader
9588 * @param {Object} meta Metadata configuration options.
9589 * @param {Object} recordType Either an Array of field definition objects
9590 * as specified to {@link Roo.data.Record#create},
9591 * or an {@link Roo.data.Record} object
9592 * created using {@link Roo.data.Record#create}.
9594 Roo.data.ArrayReader = function(meta, recordType){
9595 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9598 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9600 * Create a data block containing Roo.data.Records from an XML document.
9601 * @param {Object} o An Array of row objects which represents the dataset.
9602 * @return {Object} data A data block which is used by an Roo.data.Store object as
9603 * a cache of Roo.data.Records.
9605 readRecords : function(o){
9606 var sid = this.meta ? this.meta.id : null;
9607 var recordType = this.recordType, fields = recordType.prototype.fields;
9610 for(var i = 0; i < root.length; i++){
9613 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9614 for(var j = 0, jlen = fields.length; j < jlen; j++){
9615 var f = fields.items[j];
9616 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9617 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9621 var record = new recordType(values, id);
9623 records[records.length] = record;
9627 totalRecords : records.length
9636 * @class Roo.bootstrap.ComboBox
9637 * @extends Roo.bootstrap.TriggerField
9638 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9639 * @cfg {Boolean} append (true|false) default false
9641 * Create a new ComboBox.
9642 * @param {Object} config Configuration options
9644 Roo.bootstrap.ComboBox = function(config){
9645 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9649 * Fires when the dropdown list is expanded
9650 * @param {Roo.bootstrap.ComboBox} combo This combo box
9655 * Fires when the dropdown list is collapsed
9656 * @param {Roo.bootstrap.ComboBox} combo This combo box
9660 * @event beforeselect
9661 * Fires before a list item is selected. Return false to cancel the selection.
9662 * @param {Roo.bootstrap.ComboBox} combo This combo box
9663 * @param {Roo.data.Record} record The data record returned from the underlying store
9664 * @param {Number} index The index of the selected item in the dropdown list
9666 'beforeselect' : true,
9669 * Fires when a list item is selected
9670 * @param {Roo.bootstrap.ComboBox} combo This combo box
9671 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9672 * @param {Number} index The index of the selected item in the dropdown list
9676 * @event beforequery
9677 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9678 * The event object passed has these properties:
9679 * @param {Roo.bootstrap.ComboBox} combo This combo box
9680 * @param {String} query The query
9681 * @param {Boolean} forceAll true to force "all" query
9682 * @param {Boolean} cancel true to cancel the query
9683 * @param {Object} e The query event object
9685 'beforequery': true,
9688 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9689 * @param {Roo.bootstrap.ComboBox} combo This combo box
9694 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9695 * @param {Roo.bootstrap.ComboBox} combo This combo box
9696 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9701 * Fires when the remove value from the combobox array
9702 * @param {Roo.bootstrap.ComboBox} combo This combo box
9709 this.selectedIndex = -1;
9710 if(this.mode == 'local'){
9711 if(config.queryDelay === undefined){
9712 this.queryDelay = 10;
9714 if(config.minChars === undefined){
9720 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9723 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9724 * rendering into an Roo.Editor, defaults to false)
9727 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9728 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9731 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9734 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9735 * the dropdown list (defaults to undefined, with no header element)
9739 * @cfg {String/Roo.Template} tpl The template to use to render the output
9743 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9745 listWidth: undefined,
9747 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9748 * mode = 'remote' or 'text' if mode = 'local')
9750 displayField: undefined,
9752 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9753 * mode = 'remote' or 'value' if mode = 'local').
9754 * Note: use of a valueField requires the user make a selection
9755 * in order for a value to be mapped.
9757 valueField: undefined,
9761 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9762 * field's data value (defaults to the underlying DOM element's name)
9764 hiddenName: undefined,
9766 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9770 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9772 selectedClass: 'active',
9775 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9779 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9780 * anchor positions (defaults to 'tl-bl')
9782 listAlign: 'tl-bl?',
9784 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9788 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9789 * query specified by the allQuery config option (defaults to 'query')
9791 triggerAction: 'query',
9793 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9794 * (defaults to 4, does not apply if editable = false)
9798 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9799 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9803 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9804 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9808 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9809 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9813 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9814 * when editable = true (defaults to false)
9816 selectOnFocus:false,
9818 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9820 queryParam: 'query',
9822 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9823 * when mode = 'remote' (defaults to 'Loading...')
9825 loadingText: 'Loading...',
9827 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9831 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9835 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9836 * traditional select (defaults to true)
9840 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9844 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9848 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9849 * listWidth has a higher value)
9853 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9854 * allow the user to set arbitrary text into the field (defaults to false)
9856 forceSelection:false,
9858 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9859 * if typeAhead = true (defaults to 250)
9861 typeAheadDelay : 250,
9863 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9864 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9866 valueNotFoundText : undefined,
9868 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9873 * @cfg {Boolean} disableClear Disable showing of clear button.
9875 disableClear : false,
9877 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9879 alwaysQuery : false,
9882 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9896 // element that contains real text value.. (when hidden is used..)
9899 initEvents: function(){
9902 throw "can not find store for combo";
9904 this.store = Roo.factory(this.store, Roo.data);
9908 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9911 if(this.hiddenName){
9913 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9915 this.hiddenField.dom.value =
9916 this.hiddenValue !== undefined ? this.hiddenValue :
9917 this.value !== undefined ? this.value : '';
9919 // prevent input submission
9920 this.el.dom.removeAttribute('name');
9921 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9926 // this.el.dom.setAttribute('autocomplete', 'off');
9929 var cls = 'x-combo-list';
9930 this.list = this.el.select('ul.dropdown-menu',true).first();
9932 //this.list = new Roo.Layer({
9933 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9936 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9937 this.list.setWidth(lw);
9939 this.list.on('mouseover', this.onViewOver, this);
9940 this.list.on('mousemove', this.onViewMove, this);
9942 this.list.on('scroll', this.onViewScroll, this);
9945 this.list.swallowEvent('mousewheel');
9946 this.assetHeight = 0;
9949 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9950 this.assetHeight += this.header.getHeight();
9953 this.innerList = this.list.createChild({cls:cls+'-inner'});
9954 this.innerList.on('mouseover', this.onViewOver, this);
9955 this.innerList.on('mousemove', this.onViewMove, this);
9956 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9958 if(this.allowBlank && !this.pageSize && !this.disableClear){
9959 this.footer = this.list.createChild({cls:cls+'-ft'});
9960 this.pageTb = new Roo.Toolbar(this.footer);
9964 this.footer = this.list.createChild({cls:cls+'-ft'});
9965 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9966 {pageSize: this.pageSize});
9970 if (this.pageTb && this.allowBlank && !this.disableClear) {
9972 this.pageTb.add(new Roo.Toolbar.Fill(), {
9973 cls: 'x-btn-icon x-btn-clear',
9979 _this.onSelect(false, -1);
9984 this.assetHeight += this.footer.getHeight();
9989 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9992 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9993 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9995 //this.view.wrapEl.setDisplayed(false);
9996 this.view.on('click', this.onViewClick, this);
10000 this.store.on('beforeload', this.onBeforeLoad, this);
10001 this.store.on('load', this.onLoad, this);
10002 this.store.on('loadexception', this.onLoadException, this);
10004 if(this.resizable){
10005 this.resizer = new Roo.Resizable(this.list, {
10006 pinned:true, handles:'se'
10008 this.resizer.on('resize', function(r, w, h){
10009 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10010 this.listWidth = w;
10011 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10012 this.restrictHeight();
10014 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10017 if(!this.editable){
10018 this.editable = true;
10019 this.setEditable(false);
10024 if (typeof(this.events.add.listeners) != 'undefined') {
10026 this.addicon = this.wrap.createChild(
10027 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10029 this.addicon.on('click', function(e) {
10030 this.fireEvent('add', this);
10033 if (typeof(this.events.edit.listeners) != 'undefined') {
10035 this.editicon = this.wrap.createChild(
10036 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10037 if (this.addicon) {
10038 this.editicon.setStyle('margin-left', '40px');
10040 this.editicon.on('click', function(e) {
10042 // we fire even if inothing is selected..
10043 this.fireEvent('edit', this, this.lastData );
10049 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10050 "up" : function(e){
10051 this.inKeyMode = true;
10055 "down" : function(e){
10056 if(!this.isExpanded()){
10057 this.onTriggerClick();
10059 this.inKeyMode = true;
10064 "enter" : function(e){
10065 this.onViewClick();
10069 "esc" : function(e){
10073 "tab" : function(e){
10076 if(this.fireEvent("specialkey", this, e)){
10077 this.onViewClick(false);
10085 doRelay : function(foo, bar, hname){
10086 if(hname == 'down' || this.scope.isExpanded()){
10087 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10096 this.queryDelay = Math.max(this.queryDelay || 10,
10097 this.mode == 'local' ? 10 : 250);
10100 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10102 if(this.typeAhead){
10103 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10105 if(this.editable !== false){
10106 this.inputEl().on("keyup", this.onKeyUp, this);
10108 if(this.forceSelection){
10109 this.inputEl().on('blur', this.doForce, this);
10113 this.choices = this.el.select('ul.select2-choices', true).first();
10114 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10118 onDestroy : function(){
10120 this.view.setStore(null);
10121 this.view.el.removeAllListeners();
10122 this.view.el.remove();
10123 this.view.purgeListeners();
10126 this.list.dom.innerHTML = '';
10129 this.store.un('beforeload', this.onBeforeLoad, this);
10130 this.store.un('load', this.onLoad, this);
10131 this.store.un('loadexception', this.onLoadException, this);
10133 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10137 fireKey : function(e){
10138 if(e.isNavKeyPress() && !this.list.isVisible()){
10139 this.fireEvent("specialkey", this, e);
10144 onResize: function(w, h){
10145 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10147 // if(typeof w != 'number'){
10148 // // we do not handle it!?!?
10151 // var tw = this.trigger.getWidth();
10152 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10153 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10155 // this.inputEl().setWidth( this.adjustWidth('input', x));
10157 // //this.trigger.setStyle('left', x+'px');
10159 // if(this.list && this.listWidth === undefined){
10160 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10161 // this.list.setWidth(lw);
10162 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10170 * Allow or prevent the user from directly editing the field text. If false is passed,
10171 * the user will only be able to select from the items defined in the dropdown list. This method
10172 * is the runtime equivalent of setting the 'editable' config option at config time.
10173 * @param {Boolean} value True to allow the user to directly edit the field text
10175 setEditable : function(value){
10176 if(value == this.editable){
10179 this.editable = value;
10181 this.inputEl().dom.setAttribute('readOnly', true);
10182 this.inputEl().on('mousedown', this.onTriggerClick, this);
10183 this.inputEl().addClass('x-combo-noedit');
10185 this.inputEl().dom.setAttribute('readOnly', false);
10186 this.inputEl().un('mousedown', this.onTriggerClick, this);
10187 this.inputEl().removeClass('x-combo-noedit');
10193 onBeforeLoad : function(combo,opts){
10194 if(!this.hasFocus){
10198 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10200 this.restrictHeight();
10201 this.selectedIndex = -1;
10205 onLoad : function(){
10207 this.hasQuery = false;
10209 if(!this.hasFocus){
10213 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10214 this.loading.hide();
10217 if(this.store.getCount() > 0){
10219 this.restrictHeight();
10220 if(this.lastQuery == this.allQuery){
10222 this.inputEl().dom.select();
10224 if(!this.selectByValue(this.value, true)){
10225 this.select(0, true);
10229 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10230 this.taTask.delay(this.typeAheadDelay);
10234 this.onEmptyResults();
10240 onLoadException : function()
10242 this.hasQuery = false;
10244 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10245 this.loading.hide();
10249 Roo.log(this.store.reader.jsonData);
10250 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10252 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10258 onTypeAhead : function(){
10259 if(this.store.getCount() > 0){
10260 var r = this.store.getAt(0);
10261 var newValue = r.data[this.displayField];
10262 var len = newValue.length;
10263 var selStart = this.getRawValue().length;
10265 if(selStart != len){
10266 this.setRawValue(newValue);
10267 this.selectText(selStart, newValue.length);
10273 onSelect : function(record, index){
10275 if(this.fireEvent('beforeselect', this, record, index) !== false){
10277 this.setFromData(index > -1 ? record.data : false);
10280 this.fireEvent('select', this, record, index);
10285 * Returns the currently selected field value or empty string if no value is set.
10286 * @return {String} value The selected value
10288 getValue : function(){
10291 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10294 if(this.valueField){
10295 return typeof this.value != 'undefined' ? this.value : '';
10297 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10302 * Clears any text/value currently set in the field
10304 clearValue : function(){
10305 if(this.hiddenField){
10306 this.hiddenField.dom.value = '';
10309 this.setRawValue('');
10310 this.lastSelectionText = '';
10315 * Sets the specified value into the field. If the value finds a match, the corresponding record text
10316 * will be displayed in the field. If the value does not match the data value of an existing item,
10317 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10318 * Otherwise the field will be blank (although the value will still be set).
10319 * @param {String} value The value to match
10321 setValue : function(v){
10328 if(this.valueField){
10329 var r = this.findRecord(this.valueField, v);
10331 text = r.data[this.displayField];
10332 }else if(this.valueNotFoundText !== undefined){
10333 text = this.valueNotFoundText;
10336 this.lastSelectionText = text;
10337 if(this.hiddenField){
10338 this.hiddenField.dom.value = v;
10340 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10344 * @property {Object} the last set data for the element
10349 * Sets the value of the field based on a object which is related to the record format for the store.
10350 * @param {Object} value the value to set as. or false on reset?
10352 setFromData : function(o){
10359 var dv = ''; // display value
10360 var vv = ''; // value value..
10362 if (this.displayField) {
10363 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10365 // this is an error condition!!!
10366 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10369 if(this.valueField){
10370 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10373 if(this.hiddenField){
10374 this.hiddenField.dom.value = vv;
10376 this.lastSelectionText = dv;
10377 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10381 // no hidden field.. - we store the value in 'value', but still display
10382 // display field!!!!
10383 this.lastSelectionText = dv;
10384 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10390 reset : function(){
10391 // overridden so that last data is reset..
10392 this.setValue(this.originalValue);
10393 this.clearInvalid();
10394 this.lastData = false;
10396 this.view.clearSelections();
10400 findRecord : function(prop, value){
10402 if(this.store.getCount() > 0){
10403 this.store.each(function(r){
10404 if(r.data[prop] == value){
10414 getName: function()
10416 // returns hidden if it's set..
10417 if (!this.rendered) {return ''};
10418 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
10422 onViewMove : function(e, t){
10423 this.inKeyMode = false;
10427 onViewOver : function(e, t){
10428 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
10431 var item = this.view.findItemFromChild(t);
10433 var index = this.view.indexOf(item);
10434 this.select(index, false);
10439 onViewClick : function(doFocus)
10441 var index = this.view.getSelectedIndexes()[0];
10442 var r = this.store.getAt(index);
10444 this.onSelect(r, index);
10446 if(doFocus !== false && !this.blockFocus){
10447 this.inputEl().focus();
10452 restrictHeight : function(){
10453 //this.innerList.dom.style.height = '';
10454 //var inner = this.innerList.dom;
10455 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
10456 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
10457 //this.list.beginUpdate();
10458 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
10459 this.list.alignTo(this.inputEl(), this.listAlign);
10460 //this.list.endUpdate();
10464 onEmptyResults : function(){
10469 * Returns true if the dropdown list is expanded, else false.
10471 isExpanded : function(){
10472 return this.list.isVisible();
10476 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
10477 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
10478 * @param {String} value The data value of the item to select
10479 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
10480 * selected item if it is not currently in view (defaults to true)
10481 * @return {Boolean} True if the value matched an item in the list, else false
10483 selectByValue : function(v, scrollIntoView){
10484 if(v !== undefined && v !== null){
10485 var r = this.findRecord(this.valueField || this.displayField, v);
10487 this.select(this.store.indexOf(r), scrollIntoView);
10495 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
10496 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
10497 * @param {Number} index The zero-based index of the list item to select
10498 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
10499 * selected item if it is not currently in view (defaults to true)
10501 select : function(index, scrollIntoView){
10502 this.selectedIndex = index;
10503 this.view.select(index);
10504 if(scrollIntoView !== false){
10505 var el = this.view.getNode(index);
10507 //this.innerList.scrollChildIntoView(el, false);
10514 selectNext : function(){
10515 var ct = this.store.getCount();
10517 if(this.selectedIndex == -1){
10519 }else if(this.selectedIndex < ct-1){
10520 this.select(this.selectedIndex+1);
10526 selectPrev : function(){
10527 var ct = this.store.getCount();
10529 if(this.selectedIndex == -1){
10531 }else if(this.selectedIndex != 0){
10532 this.select(this.selectedIndex-1);
10538 onKeyUp : function(e){
10539 if(this.editable !== false && !e.isSpecialKey()){
10540 this.lastKey = e.getKey();
10541 this.dqTask.delay(this.queryDelay);
10546 validateBlur : function(){
10547 return !this.list || !this.list.isVisible();
10551 initQuery : function(){
10552 this.doQuery(this.getRawValue());
10556 doForce : function(){
10557 if(this.inputEl().dom.value.length > 0){
10558 this.inputEl().dom.value =
10559 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
10565 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
10566 * query allowing the query action to be canceled if needed.
10567 * @param {String} query The SQL query to execute
10568 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
10569 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
10570 * saved in the current store (defaults to false)
10572 doQuery : function(q, forceAll){
10574 if(q === undefined || q === null){
10579 forceAll: forceAll,
10583 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
10588 forceAll = qe.forceAll;
10589 if(forceAll === true || (q.length >= this.minChars)){
10591 this.hasQuery = true;
10593 if(this.lastQuery != q || this.alwaysQuery){
10594 this.lastQuery = q;
10595 if(this.mode == 'local'){
10596 this.selectedIndex = -1;
10598 this.store.clearFilter();
10600 this.store.filter(this.displayField, q);
10604 this.store.baseParams[this.queryParam] = q;
10606 var options = {params : this.getParams(q)};
10609 options.add = true;
10610 options.params.start = this.page * this.pageSize;
10613 this.store.load(options);
10617 this.selectedIndex = -1;
10622 this.loadNext = false;
10626 getParams : function(q){
10628 //p[this.queryParam] = q;
10632 p.limit = this.pageSize;
10638 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
10640 collapse : function(){
10641 if(!this.isExpanded()){
10646 Roo.get(document).un('mousedown', this.collapseIf, this);
10647 Roo.get(document).un('mousewheel', this.collapseIf, this);
10648 if (!this.editable) {
10649 Roo.get(document).un('keydown', this.listKeyPress, this);
10651 this.fireEvent('collapse', this);
10655 collapseIf : function(e){
10656 var in_combo = e.within(this.el);
10657 var in_list = e.within(this.list);
10659 if (in_combo || in_list) {
10660 //e.stopPropagation();
10669 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
10671 expand : function(){
10673 if(this.isExpanded() || !this.hasFocus){
10677 this.list.alignTo(this.inputEl(), this.listAlign);
10679 Roo.get(document).on('mousedown', this.collapseIf, this);
10680 Roo.get(document).on('mousewheel', this.collapseIf, this);
10681 if (!this.editable) {
10682 Roo.get(document).on('keydown', this.listKeyPress, this);
10685 this.fireEvent('expand', this);
10689 // Implements the default empty TriggerField.onTriggerClick function
10690 onTriggerClick : function()
10692 Roo.log('trigger click');
10699 this.loadNext = false;
10701 if(this.isExpanded()){
10703 if (!this.blockFocus) {
10704 this.inputEl().focus();
10708 this.hasFocus = true;
10709 if(this.triggerAction == 'all') {
10710 this.doQuery(this.allQuery, true);
10712 this.doQuery(this.getRawValue());
10714 if (!this.blockFocus) {
10715 this.inputEl().focus();
10719 listKeyPress : function(e)
10721 //Roo.log('listkeypress');
10722 // scroll to first matching element based on key pres..
10723 if (e.isSpecialKey()) {
10726 var k = String.fromCharCode(e.getKey()).toUpperCase();
10729 var csel = this.view.getSelectedNodes();
10730 var cselitem = false;
10732 var ix = this.view.indexOf(csel[0]);
10733 cselitem = this.store.getAt(ix);
10734 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10740 this.store.each(function(v) {
10742 // start at existing selection.
10743 if (cselitem.id == v.id) {
10749 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10750 match = this.store.indexOf(v);
10756 if (match === false) {
10757 return true; // no more action?
10760 this.view.select(match);
10761 var sn = Roo.get(this.view.getSelectedNodes()[0])
10762 //sn.scrollIntoView(sn.dom.parentNode, false);
10765 onViewScroll : function(e, t){
10767 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10771 this.hasQuery = true;
10773 this.loading = this.list.select('.loading', true).first();
10775 if(this.loading === null){
10776 this.list.createChild({
10778 cls: 'loading select2-more-results select2-active',
10779 html: 'Loading more results...'
10782 this.loading = this.list.select('.loading', true).first();
10784 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10786 this.loading.hide();
10789 this.loading.show();
10794 this.loadNext = true;
10796 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10801 addItem : function(o)
10803 var dv = ''; // display value
10805 if (this.displayField) {
10806 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10808 // this is an error condition!!!
10809 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10816 var choice = this.choices.createChild({
10818 cls: 'select2-search-choice',
10827 cls: 'select2-search-choice-close',
10832 }, this.searchField);
10834 var close = choice.select('a.select2-search-choice-close', true).first()
10836 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10843 this.inputEl().dom.value = '';
10847 onRemoveItem : function(e, _self, o)
10849 e.preventDefault();
10850 var index = this.item.indexOf(o.data) * 1;
10853 Roo.log('not this item?!');
10857 this.item.splice(index, 1);
10862 this.fireEvent('remove', this, e);
10866 syncValue : function()
10868 if(!this.item.length){
10875 Roo.each(this.item, function(i){
10876 if(_this.valueField){
10877 value.push(i[_this.valueField]);
10884 this.value = value.join(',');
10886 if(this.hiddenField){
10887 this.hiddenField.dom.value = this.value;
10891 clearItem : function()
10893 if(!this.multiple){
10899 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10909 * @cfg {Boolean} grow
10913 * @cfg {Number} growMin
10917 * @cfg {Number} growMax
10927 * Ext JS Library 1.1.1
10928 * Copyright(c) 2006-2007, Ext JS, LLC.
10930 * Originally Released Under LGPL - original licence link has changed is not relivant.
10933 * <script type="text/javascript">
10938 * @extends Roo.util.Observable
10939 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10940 * This class also supports single and multi selection modes. <br>
10941 * Create a data model bound view:
10943 var store = new Roo.data.Store(...);
10945 var view = new Roo.View({
10947 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10949 singleSelect: true,
10950 selectedClass: "ydataview-selected",
10954 // listen for node click?
10955 view.on("click", function(vw, index, node, e){
10956 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10960 dataModel.load("foobar.xml");
10962 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10964 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10965 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10967 * Note: old style constructor is still suported (container, template, config)
10970 * Create a new View
10971 * @param {Object} config The config object
10974 Roo.View = function(config, depreciated_tpl, depreciated_config){
10976 if (typeof(depreciated_tpl) == 'undefined') {
10977 // new way.. - universal constructor.
10978 Roo.apply(this, config);
10979 this.el = Roo.get(this.el);
10982 this.el = Roo.get(config);
10983 this.tpl = depreciated_tpl;
10984 Roo.apply(this, depreciated_config);
10986 this.wrapEl = this.el.wrap().wrap();
10987 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10990 if(typeof(this.tpl) == "string"){
10991 this.tpl = new Roo.Template(this.tpl);
10993 // support xtype ctors..
10994 this.tpl = new Roo.factory(this.tpl, Roo);
10998 this.tpl.compile();
11006 * @event beforeclick
11007 * Fires before a click is processed. Returns false to cancel the default action.
11008 * @param {Roo.View} this
11009 * @param {Number} index The index of the target node
11010 * @param {HTMLElement} node The target node
11011 * @param {Roo.EventObject} e The raw event object
11013 "beforeclick" : true,
11016 * Fires when a template node is clicked.
11017 * @param {Roo.View} this
11018 * @param {Number} index The index of the target node
11019 * @param {HTMLElement} node The target node
11020 * @param {Roo.EventObject} e The raw event object
11025 * Fires when a template node is double clicked.
11026 * @param {Roo.View} this
11027 * @param {Number} index The index of the target node
11028 * @param {HTMLElement} node The target node
11029 * @param {Roo.EventObject} e The raw event object
11033 * @event contextmenu
11034 * Fires when a template node is right clicked.
11035 * @param {Roo.View} this
11036 * @param {Number} index The index of the target node
11037 * @param {HTMLElement} node The target node
11038 * @param {Roo.EventObject} e The raw event object
11040 "contextmenu" : true,
11042 * @event selectionchange
11043 * Fires when the selected nodes change.
11044 * @param {Roo.View} this
11045 * @param {Array} selections Array of the selected nodes
11047 "selectionchange" : true,
11050 * @event beforeselect
11051 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11052 * @param {Roo.View} this
11053 * @param {HTMLElement} node The node to be selected
11054 * @param {Array} selections Array of currently selected nodes
11056 "beforeselect" : true,
11058 * @event preparedata
11059 * Fires on every row to render, to allow you to change the data.
11060 * @param {Roo.View} this
11061 * @param {Object} data to be rendered (change this)
11063 "preparedata" : true
11071 "click": this.onClick,
11072 "dblclick": this.onDblClick,
11073 "contextmenu": this.onContextMenu,
11077 this.selections = [];
11079 this.cmp = new Roo.CompositeElementLite([]);
11081 this.store = Roo.factory(this.store, Roo.data);
11082 this.setStore(this.store, true);
11085 if ( this.footer && this.footer.xtype) {
11087 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11089 this.footer.dataSource = this.store
11090 this.footer.container = fctr;
11091 this.footer = Roo.factory(this.footer, Roo);
11092 fctr.insertFirst(this.el);
11094 // this is a bit insane - as the paging toolbar seems to detach the el..
11095 // dom.parentNode.parentNode.parentNode
11096 // they get detached?
11100 Roo.View.superclass.constructor.call(this);
11105 Roo.extend(Roo.View, Roo.util.Observable, {
11108 * @cfg {Roo.data.Store} store Data store to load data from.
11113 * @cfg {String|Roo.Element} el The container element.
11118 * @cfg {String|Roo.Template} tpl The template used by this View
11122 * @cfg {String} dataName the named area of the template to use as the data area
11123 * Works with domtemplates roo-name="name"
11127 * @cfg {String} selectedClass The css class to add to selected nodes
11129 selectedClass : "x-view-selected",
11131 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11136 * @cfg {String} text to display on mask (default Loading)
11140 * @cfg {Boolean} multiSelect Allow multiple selection
11142 multiSelect : false,
11144 * @cfg {Boolean} singleSelect Allow single selection
11146 singleSelect: false,
11149 * @cfg {Boolean} toggleSelect - selecting
11151 toggleSelect : false,
11154 * Returns the element this view is bound to.
11155 * @return {Roo.Element}
11157 getEl : function(){
11158 return this.wrapEl;
11164 * Refreshes the view. - called by datachanged on the store. - do not call directly.
11166 refresh : function(){
11167 Roo.log('refresh');
11170 // if we are using something like 'domtemplate', then
11171 // the what gets used is:
11172 // t.applySubtemplate(NAME, data, wrapping data..)
11173 // the outer template then get' applied with
11174 // the store 'extra data'
11175 // and the body get's added to the
11176 // roo-name="data" node?
11177 // <span class='roo-tpl-{name}'></span> ?????
11181 this.clearSelections();
11182 this.el.update("");
11184 var records = this.store.getRange();
11185 if(records.length < 1) {
11187 // is this valid?? = should it render a template??
11189 this.el.update(this.emptyText);
11193 if (this.dataName) {
11194 this.el.update(t.apply(this.store.meta)); //????
11195 el = this.el.child('.roo-tpl-' + this.dataName);
11198 for(var i = 0, len = records.length; i < len; i++){
11199 var data = this.prepareData(records[i].data, i, records[i]);
11200 this.fireEvent("preparedata", this, data, i, records[i]);
11201 html[html.length] = Roo.util.Format.trim(
11203 t.applySubtemplate(this.dataName, data, this.store.meta) :
11210 el.update(html.join(""));
11211 this.nodes = el.dom.childNodes;
11212 this.updateIndexes(0);
11217 * Function to override to reformat the data that is sent to
11218 * the template for each node.
11219 * DEPRICATED - use the preparedata event handler.
11220 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11221 * a JSON object for an UpdateManager bound view).
11223 prepareData : function(data, index, record)
11225 this.fireEvent("preparedata", this, data, index, record);
11229 onUpdate : function(ds, record){
11230 Roo.log('on update');
11231 this.clearSelections();
11232 var index = this.store.indexOf(record);
11233 var n = this.nodes[index];
11234 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11235 n.parentNode.removeChild(n);
11236 this.updateIndexes(index, index);
11242 onAdd : function(ds, records, index)
11244 Roo.log(['on Add', ds, records, index] );
11245 this.clearSelections();
11246 if(this.nodes.length == 0){
11250 var n = this.nodes[index];
11251 for(var i = 0, len = records.length; i < len; i++){
11252 var d = this.prepareData(records[i].data, i, records[i]);
11254 this.tpl.insertBefore(n, d);
11257 this.tpl.append(this.el, d);
11260 this.updateIndexes(index);
11263 onRemove : function(ds, record, index){
11264 Roo.log('onRemove');
11265 this.clearSelections();
11266 var el = this.dataName ?
11267 this.el.child('.roo-tpl-' + this.dataName) :
11270 el.dom.removeChild(this.nodes[index]);
11271 this.updateIndexes(index);
11275 * Refresh an individual node.
11276 * @param {Number} index
11278 refreshNode : function(index){
11279 this.onUpdate(this.store, this.store.getAt(index));
11282 updateIndexes : function(startIndex, endIndex){
11283 var ns = this.nodes;
11284 startIndex = startIndex || 0;
11285 endIndex = endIndex || ns.length - 1;
11286 for(var i = startIndex; i <= endIndex; i++){
11287 ns[i].nodeIndex = i;
11292 * Changes the data store this view uses and refresh the view.
11293 * @param {Store} store
11295 setStore : function(store, initial){
11296 if(!initial && this.store){
11297 this.store.un("datachanged", this.refresh);
11298 this.store.un("add", this.onAdd);
11299 this.store.un("remove", this.onRemove);
11300 this.store.un("update", this.onUpdate);
11301 this.store.un("clear", this.refresh);
11302 this.store.un("beforeload", this.onBeforeLoad);
11303 this.store.un("load", this.onLoad);
11304 this.store.un("loadexception", this.onLoad);
11308 store.on("datachanged", this.refresh, this);
11309 store.on("add", this.onAdd, this);
11310 store.on("remove", this.onRemove, this);
11311 store.on("update", this.onUpdate, this);
11312 store.on("clear", this.refresh, this);
11313 store.on("beforeload", this.onBeforeLoad, this);
11314 store.on("load", this.onLoad, this);
11315 store.on("loadexception", this.onLoad, this);
11323 * onbeforeLoad - masks the loading area.
11326 onBeforeLoad : function(store,opts)
11328 Roo.log('onBeforeLoad');
11330 this.el.update("");
11332 this.el.mask(this.mask ? this.mask : "Loading" );
11334 onLoad : function ()
11341 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
11342 * @param {HTMLElement} node
11343 * @return {HTMLElement} The template node
11345 findItemFromChild : function(node){
11346 var el = this.dataName ?
11347 this.el.child('.roo-tpl-' + this.dataName,true) :
11350 if(!node || node.parentNode == el){
11353 var p = node.parentNode;
11354 while(p && p != el){
11355 if(p.parentNode == el){
11364 onClick : function(e){
11365 var item = this.findItemFromChild(e.getTarget());
11367 var index = this.indexOf(item);
11368 if(this.onItemClick(item, index, e) !== false){
11369 this.fireEvent("click", this, index, item, e);
11372 this.clearSelections();
11377 onContextMenu : function(e){
11378 var item = this.findItemFromChild(e.getTarget());
11380 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
11385 onDblClick : function(e){
11386 var item = this.findItemFromChild(e.getTarget());
11388 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
11392 onItemClick : function(item, index, e)
11394 if(this.fireEvent("beforeclick", this, index, item, e) === false){
11397 if (this.toggleSelect) {
11398 var m = this.isSelected(item) ? 'unselect' : 'select';
11401 _t[m](item, true, false);
11404 if(this.multiSelect || this.singleSelect){
11405 if(this.multiSelect && e.shiftKey && this.lastSelection){
11406 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
11408 this.select(item, this.multiSelect && e.ctrlKey);
11409 this.lastSelection = item;
11411 e.preventDefault();
11417 * Get the number of selected nodes.
11420 getSelectionCount : function(){
11421 return this.selections.length;
11425 * Get the currently selected nodes.
11426 * @return {Array} An array of HTMLElements
11428 getSelectedNodes : function(){
11429 return this.selections;
11433 * Get the indexes of the selected nodes.
11436 getSelectedIndexes : function(){
11437 var indexes = [], s = this.selections;
11438 for(var i = 0, len = s.length; i < len; i++){
11439 indexes.push(s[i].nodeIndex);
11445 * Clear all selections
11446 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
11448 clearSelections : function(suppressEvent){
11449 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
11450 this.cmp.elements = this.selections;
11451 this.cmp.removeClass(this.selectedClass);
11452 this.selections = [];
11453 if(!suppressEvent){
11454 this.fireEvent("selectionchange", this, this.selections);
11460 * Returns true if the passed node is selected
11461 * @param {HTMLElement/Number} node The node or node index
11462 * @return {Boolean}
11464 isSelected : function(node){
11465 var s = this.selections;
11469 node = this.getNode(node);
11470 return s.indexOf(node) !== -1;
11475 * @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
11476 * @param {Boolean} keepExisting (optional) true to keep existing selections
11477 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
11479 select : function(nodeInfo, keepExisting, suppressEvent){
11480 if(nodeInfo instanceof Array){
11482 this.clearSelections(true);
11484 for(var i = 0, len = nodeInfo.length; i < len; i++){
11485 this.select(nodeInfo[i], true, true);
11489 var node = this.getNode(nodeInfo);
11490 if(!node || this.isSelected(node)){
11491 return; // already selected.
11494 this.clearSelections(true);
11496 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
11497 Roo.fly(node).addClass(this.selectedClass);
11498 this.selections.push(node);
11499 if(!suppressEvent){
11500 this.fireEvent("selectionchange", this, this.selections);
11508 * @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
11509 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
11510 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
11512 unselect : function(nodeInfo, keepExisting, suppressEvent)
11514 if(nodeInfo instanceof Array){
11515 Roo.each(this.selections, function(s) {
11516 this.unselect(s, nodeInfo);
11520 var node = this.getNode(nodeInfo);
11521 if(!node || !this.isSelected(node)){
11522 Roo.log("not selected");
11523 return; // not selected.
11527 Roo.each(this.selections, function(s) {
11529 Roo.fly(node).removeClass(this.selectedClass);
11536 this.selections= ns;
11537 this.fireEvent("selectionchange", this, this.selections);
11541 * Gets a template node.
11542 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11543 * @return {HTMLElement} The node or null if it wasn't found
11545 getNode : function(nodeInfo){
11546 if(typeof nodeInfo == "string"){
11547 return document.getElementById(nodeInfo);
11548 }else if(typeof nodeInfo == "number"){
11549 return this.nodes[nodeInfo];
11555 * Gets a range template nodes.
11556 * @param {Number} startIndex
11557 * @param {Number} endIndex
11558 * @return {Array} An array of nodes
11560 getNodes : function(start, end){
11561 var ns = this.nodes;
11562 start = start || 0;
11563 end = typeof end == "undefined" ? ns.length - 1 : end;
11566 for(var i = start; i <= end; i++){
11570 for(var i = start; i >= end; i--){
11578 * Finds the index of the passed node
11579 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11580 * @return {Number} The index of the node or -1
11582 indexOf : function(node){
11583 node = this.getNode(node);
11584 if(typeof node.nodeIndex == "number"){
11585 return node.nodeIndex;
11587 var ns = this.nodes;
11588 for(var i = 0, len = ns.length; i < len; i++){
11599 * based on jquery fullcalendar
11603 Roo.bootstrap = Roo.bootstrap || {};
11605 * @class Roo.bootstrap.Calendar
11606 * @extends Roo.bootstrap.Component
11607 * Bootstrap Calendar class
11608 * @cfg {Boolean} loadMask (true|false) default false
11609 * @cfg {Object} header generate the user specific header of the calendar, default false
11612 * Create a new Container
11613 * @param {Object} config The config object
11618 Roo.bootstrap.Calendar = function(config){
11619 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
11623 * Fires when a date is selected
11624 * @param {DatePicker} this
11625 * @param {Date} date The selected date
11629 * @event monthchange
11630 * Fires when the displayed month changes
11631 * @param {DatePicker} this
11632 * @param {Date} date The selected month
11634 'monthchange': true,
11636 * @event evententer
11637 * Fires when mouse over an event
11638 * @param {Calendar} this
11639 * @param {event} Event
11641 'evententer': true,
11643 * @event eventleave
11644 * Fires when the mouse leaves an
11645 * @param {Calendar} this
11648 'eventleave': true,
11650 * @event eventclick
11651 * Fires when the mouse click an
11652 * @param {Calendar} this
11661 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
11664 * @cfg {Number} startDay
11665 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11673 getAutoCreate : function(){
11676 var fc_button = function(name, corner, style, content ) {
11677 return Roo.apply({},{
11679 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
11681 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
11684 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11695 style : 'width:100%',
11702 cls : 'fc-header-left',
11704 fc_button('prev', 'left', 'arrow', '‹' ),
11705 fc_button('next', 'right', 'arrow', '›' ),
11706 { tag: 'span', cls: 'fc-header-space' },
11707 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11715 cls : 'fc-header-center',
11719 cls: 'fc-header-title',
11722 html : 'month / year'
11730 cls : 'fc-header-right',
11732 /* fc_button('month', 'left', '', 'month' ),
11733 fc_button('week', '', '', 'week' ),
11734 fc_button('day', 'right', '', 'day' )
11746 header = this.header;
11749 var cal_heads = function() {
11751 // fixme - handle this.
11753 for (var i =0; i < Date.dayNames.length; i++) {
11754 var d = Date.dayNames[i];
11757 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11758 html : d.substring(0,3)
11762 ret[0].cls += ' fc-first';
11763 ret[6].cls += ' fc-last';
11766 var cal_cell = function(n) {
11769 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11774 cls: 'fc-day-number',
11778 cls: 'fc-day-content',
11782 style: 'position: relative;' // height: 17px;
11794 var cal_rows = function() {
11797 for (var r = 0; r < 6; r++) {
11804 for (var i =0; i < Date.dayNames.length; i++) {
11805 var d = Date.dayNames[i];
11806 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11809 row.cn[0].cls+=' fc-first';
11810 row.cn[0].cn[0].style = 'min-height:90px';
11811 row.cn[6].cls+=' fc-last';
11815 ret[0].cls += ' fc-first';
11816 ret[4].cls += ' fc-prev-last';
11817 ret[5].cls += ' fc-last';
11824 cls: 'fc-border-separate',
11825 style : 'width:100%',
11833 cls : 'fc-first fc-last',
11851 cls : 'fc-content',
11852 style : "position: relative;",
11855 cls : 'fc-view fc-view-month fc-grid',
11856 style : 'position: relative',
11857 unselectable : 'on',
11860 cls : 'fc-event-container',
11861 style : 'position:absolute;z-index:8;top:0;left:0;'
11879 initEvents : function()
11882 throw "can not find store for calendar";
11888 style: "text-align:center",
11892 style: "background-color:white;width:50%;margin:250 auto",
11896 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
11907 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11909 var size = this.el.select('.fc-content', true).first().getSize();
11910 this.maskEl.setSize(size.width, size.height);
11911 this.maskEl.enableDisplayMode("block");
11912 if(!this.loadMask){
11913 this.maskEl.hide();
11916 this.store = Roo.factory(this.store, Roo.data);
11917 this.store.on('load', this.onLoad, this);
11918 this.store.on('beforeload', this.onBeforeLoad, this);
11922 this.cells = this.el.select('.fc-day',true);
11923 //Roo.log(this.cells);
11924 this.textNodes = this.el.query('.fc-day-number');
11925 this.cells.addClassOnOver('fc-state-hover');
11927 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11928 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11929 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11930 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11932 this.on('monthchange', this.onMonthChange, this);
11934 this.update(new Date().clearTime());
11937 resize : function() {
11938 var sz = this.el.getSize();
11940 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11941 this.el.select('.fc-day-content div',true).setHeight(34);
11946 showPrevMonth : function(e){
11947 this.update(this.activeDate.add("mo", -1));
11949 showToday : function(e){
11950 this.update(new Date().clearTime());
11953 showNextMonth : function(e){
11954 this.update(this.activeDate.add("mo", 1));
11958 showPrevYear : function(){
11959 this.update(this.activeDate.add("y", -1));
11963 showNextYear : function(){
11964 this.update(this.activeDate.add("y", 1));
11969 update : function(date)
11971 var vd = this.activeDate;
11972 this.activeDate = date;
11973 // if(vd && this.el){
11974 // var t = date.getTime();
11975 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11976 // Roo.log('using add remove');
11978 // this.fireEvent('monthchange', this, date);
11980 // this.cells.removeClass("fc-state-highlight");
11981 // this.cells.each(function(c){
11982 // if(c.dateValue == t){
11983 // c.addClass("fc-state-highlight");
11984 // setTimeout(function(){
11985 // try{c.dom.firstChild.focus();}catch(e){}
11995 var days = date.getDaysInMonth();
11997 var firstOfMonth = date.getFirstDateOfMonth();
11998 var startingPos = firstOfMonth.getDay()-this.startDay;
12000 if(startingPos < this.startDay){
12004 var pm = date.add(Date.MONTH, -1);
12005 var prevStart = pm.getDaysInMonth()-startingPos;
12007 this.cells = this.el.select('.fc-day',true);
12008 this.textNodes = this.el.query('.fc-day-number');
12009 this.cells.addClassOnOver('fc-state-hover');
12011 var cells = this.cells.elements;
12012 var textEls = this.textNodes;
12014 Roo.each(cells, function(cell){
12015 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12018 days += startingPos;
12020 // convert everything to numbers so it's fast
12021 var day = 86400000;
12022 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12025 //Roo.log(prevStart);
12027 var today = new Date().clearTime().getTime();
12028 var sel = date.clearTime().getTime();
12029 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12030 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12031 var ddMatch = this.disabledDatesRE;
12032 var ddText = this.disabledDatesText;
12033 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12034 var ddaysText = this.disabledDaysText;
12035 var format = this.format;
12037 var setCellClass = function(cal, cell){
12041 //Roo.log('set Cell Class');
12043 var t = d.getTime();
12047 cell.dateValue = t;
12049 cell.className += " fc-today";
12050 cell.className += " fc-state-highlight";
12051 cell.title = cal.todayText;
12054 // disable highlight in other month..
12055 //cell.className += " fc-state-highlight";
12060 cell.className = " fc-state-disabled";
12061 cell.title = cal.minText;
12065 cell.className = " fc-state-disabled";
12066 cell.title = cal.maxText;
12070 if(ddays.indexOf(d.getDay()) != -1){
12071 cell.title = ddaysText;
12072 cell.className = " fc-state-disabled";
12075 if(ddMatch && format){
12076 var fvalue = d.dateFormat(format);
12077 if(ddMatch.test(fvalue)){
12078 cell.title = ddText.replace("%0", fvalue);
12079 cell.className = " fc-state-disabled";
12083 if (!cell.initialClassName) {
12084 cell.initialClassName = cell.dom.className;
12087 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12092 for(; i < startingPos; i++) {
12093 textEls[i].innerHTML = (++prevStart);
12094 d.setDate(d.getDate()+1);
12096 cells[i].className = "fc-past fc-other-month";
12097 setCellClass(this, cells[i]);
12102 for(; i < days; i++){
12103 intDay = i - startingPos + 1;
12104 textEls[i].innerHTML = (intDay);
12105 d.setDate(d.getDate()+1);
12107 cells[i].className = ''; // "x-date-active";
12108 setCellClass(this, cells[i]);
12112 for(; i < 42; i++) {
12113 textEls[i].innerHTML = (++extraDays);
12114 d.setDate(d.getDate()+1);
12116 cells[i].className = "fc-future fc-other-month";
12117 setCellClass(this, cells[i]);
12120 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12122 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12124 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12125 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12127 if(totalRows != 6){
12128 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12129 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12132 this.fireEvent('monthchange', this, date);
12136 if(!this.internalRender){
12137 var main = this.el.dom.firstChild;
12138 var w = main.offsetWidth;
12139 this.el.setWidth(w + this.el.getBorderWidth("lr"));
12140 Roo.fly(main).setWidth(w);
12141 this.internalRender = true;
12142 // opera does not respect the auto grow header center column
12143 // then, after it gets a width opera refuses to recalculate
12144 // without a second pass
12145 if(Roo.isOpera && !this.secondPass){
12146 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12147 this.secondPass = true;
12148 this.update.defer(10, this, [date]);
12155 findCell : function(dt) {
12156 dt = dt.clearTime().getTime();
12158 this.cells.each(function(c){
12159 //Roo.log("check " +c.dateValue + '?=' + dt);
12160 if(c.dateValue == dt){
12170 findCells : function(ev) {
12171 var s = ev.start.clone().clearTime().getTime();
12173 var e= ev.end.clone().clearTime().getTime();
12176 this.cells.each(function(c){
12177 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12179 if(c.dateValue > e){
12182 if(c.dateValue < s){
12191 // findBestRow: function(cells)
12195 // for (var i =0 ; i < cells.length;i++) {
12196 // ret = Math.max(cells[i].rows || 0,ret);
12203 addItem : function(ev)
12205 // look for vertical location slot in
12206 var cells = this.findCells(ev);
12208 // ev.row = this.findBestRow(cells);
12210 // work out the location.
12214 for(var i =0; i < cells.length; i++) {
12216 cells[i].row = cells[0].row;
12219 cells[i].row = cells[i].row + 1;
12229 if (crow.start.getY() == cells[i].getY()) {
12231 crow.end = cells[i];
12248 cells[0].events.push(ev);
12250 this.calevents.push(ev);
12253 clearEvents: function() {
12255 if(!this.calevents){
12259 Roo.each(this.cells.elements, function(c){
12265 Roo.each(this.calevents, function(e) {
12266 Roo.each(e.els, function(el) {
12267 el.un('mouseenter' ,this.onEventEnter, this);
12268 el.un('mouseleave' ,this.onEventLeave, this);
12273 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
12279 renderEvents: function()
12283 this.cells.each(function(c) {
12292 if(c.row != c.events.length){
12293 r = 4 - (4 - (c.row - c.events.length));
12296 c.events = ev.slice(0, r);
12297 c.more = ev.slice(r);
12299 if(c.more.length && c.more.length == 1){
12300 c.events.push(c.more.pop());
12303 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
12307 this.cells.each(function(c) {
12309 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
12312 for (var e = 0; e < c.events.length; e++){
12313 var ev = c.events[e];
12314 var rows = ev.rows;
12316 for(var i = 0; i < rows.length; i++) {
12318 // how many rows should it span..
12321 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
12322 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
12324 unselectable : "on",
12327 cls: 'fc-event-inner',
12331 // cls: 'fc-event-time',
12332 // html : cells.length > 1 ? '' : ev.time
12336 cls: 'fc-event-title',
12337 html : String.format('{0}', ev.title)
12344 cls: 'ui-resizable-handle ui-resizable-e',
12345 html : '  '
12352 cfg.cls += ' fc-event-start';
12354 if ((i+1) == rows.length) {
12355 cfg.cls += ' fc-event-end';
12358 var ctr = _this.el.select('.fc-event-container',true).first();
12359 var cg = ctr.createChild(cfg);
12361 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
12362 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
12364 var r = (c.more.length) ? 1 : 0;
12365 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
12366 cg.setWidth(ebox.right - sbox.x -2);
12368 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
12369 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
12370 cg.on('click', _this.onEventClick, _this, ev);
12381 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
12382 style : 'position: absolute',
12383 unselectable : "on",
12386 cls: 'fc-event-inner',
12390 cls: 'fc-event-title',
12398 cls: 'ui-resizable-handle ui-resizable-e',
12399 html : '  '
12405 var ctr = _this.el.select('.fc-event-container',true).first();
12406 var cg = ctr.createChild(cfg);
12408 var sbox = c.select('.fc-day-content',true).first().getBox();
12409 var ebox = c.select('.fc-day-content',true).first().getBox();
12411 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
12412 cg.setWidth(ebox.right - sbox.x -2);
12414 cg.on('click', _this.onMoreEventClick, _this, c.more);
12424 onEventEnter: function (e, el,event,d) {
12425 this.fireEvent('evententer', this, el, event);
12428 onEventLeave: function (e, el,event,d) {
12429 this.fireEvent('eventleave', this, el, event);
12432 onEventClick: function (e, el,event,d) {
12433 this.fireEvent('eventclick', this, el, event);
12436 onMonthChange: function () {
12440 onMoreEventClick: function(e, el, more)
12444 this.calpopover.placement = 'right';
12445 this.calpopover.setTitle('More');
12447 this.calpopover.setContent('');
12449 var ctr = this.calpopover.el.select('.popover-content', true).first();
12451 Roo.each(more, function(m){
12453 cls : 'fc-event-hori fc-event-draggable',
12456 var cg = ctr.createChild(cfg);
12458 cg.on('click', _this.onEventClick, _this, m);
12461 this.calpopover.show(el);
12466 onLoad: function ()
12468 this.calevents = [];
12471 if(this.store.getCount() > 0){
12472 this.store.data.each(function(d){
12475 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
12476 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
12477 time : d.data.start_time,
12478 title : d.data.title,
12479 description : d.data.description,
12480 venue : d.data.venue
12485 this.renderEvents();
12487 if(this.calevents.length && this.loadMask){
12488 this.maskEl.hide();
12492 onBeforeLoad: function()
12494 this.clearEvents();
12496 this.maskEl.show();
12510 * @class Roo.bootstrap.Popover
12511 * @extends Roo.bootstrap.Component
12512 * Bootstrap Popover class
12513 * @cfg {String} html contents of the popover (or false to use children..)
12514 * @cfg {String} title of popover (or false to hide)
12515 * @cfg {String} placement how it is placed
12516 * @cfg {String} trigger click || hover (or false to trigger manually)
12517 * @cfg {String} over what (parent or false to trigger manually.)
12520 * Create a new Popover
12521 * @param {Object} config The config object
12524 Roo.bootstrap.Popover = function(config){
12525 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
12528 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
12530 title: 'Fill in a title',
12533 placement : 'right',
12534 trigger : 'hover', // hover
12538 can_build_overlaid : false,
12540 getChildContainer : function()
12542 return this.el.select('.popover-content',true).first();
12545 getAutoCreate : function(){
12546 Roo.log('make popover?');
12548 cls : 'popover roo-dynamic',
12549 style: 'display:block',
12555 cls : 'popover-inner',
12559 cls: 'popover-title',
12563 cls : 'popover-content',
12574 setTitle: function(str)
12576 this.el.select('.popover-title',true).first().dom.innerHTML = str;
12578 setContent: function(str)
12580 this.el.select('.popover-content',true).first().dom.innerHTML = str;
12582 // as it get's added to the bottom of the page.
12583 onRender : function(ct, position)
12585 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
12587 var cfg = Roo.apply({}, this.getAutoCreate());
12591 cfg.cls += ' ' + this.cls;
12594 cfg.style = this.style;
12596 Roo.log("adding to ")
12597 this.el = Roo.get(document.body).createChild(cfg, position);
12603 initEvents : function()
12605 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
12606 this.el.enableDisplayMode('block');
12608 if (this.over === false) {
12611 if (this.triggers === false) {
12614 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12615 var triggers = this.trigger ? this.trigger.split(' ') : [];
12616 Roo.each(triggers, function(trigger) {
12618 if (trigger == 'click') {
12619 on_el.on('click', this.toggle, this);
12620 } else if (trigger != 'manual') {
12621 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
12622 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
12624 on_el.on(eventIn ,this.enter, this);
12625 on_el.on(eventOut, this.leave, this);
12636 toggle : function () {
12637 this.hoverState == 'in' ? this.leave() : this.enter();
12640 enter : function () {
12643 clearTimeout(this.timeout);
12645 this.hoverState = 'in'
12647 if (!this.delay || !this.delay.show) {
12652 this.timeout = setTimeout(function () {
12653 if (_t.hoverState == 'in') {
12656 }, this.delay.show)
12658 leave : function() {
12659 clearTimeout(this.timeout);
12661 this.hoverState = 'out'
12663 if (!this.delay || !this.delay.hide) {
12668 this.timeout = setTimeout(function () {
12669 if (_t.hoverState == 'out') {
12672 }, this.delay.hide)
12675 show : function (on_el)
12678 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12681 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
12682 if (this.html !== false) {
12683 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
12685 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
12686 if (!this.title.length) {
12687 this.el.select('.popover-title',true).hide();
12690 var placement = typeof this.placement == 'function' ?
12691 this.placement.call(this, this.el, on_el) :
12694 var autoToken = /\s?auto?\s?/i;
12695 var autoPlace = autoToken.test(placement);
12697 placement = placement.replace(autoToken, '') || 'top';
12701 //this.el.setXY([0,0]);
12703 this.el.dom.style.display='block';
12704 this.el.addClass(placement);
12706 //this.el.appendTo(on_el);
12708 var p = this.getPosition();
12709 var box = this.el.getBox();
12714 var align = Roo.bootstrap.Popover.alignment[placement]
12715 this.el.alignTo(on_el, align[0],align[1]);
12716 //var arrow = this.el.select('.arrow',true).first();
12717 //arrow.set(align[2],
12719 this.el.addClass('in');
12720 this.hoverState = null;
12722 if (this.el.hasClass('fade')) {
12729 this.el.setXY([0,0]);
12730 this.el.removeClass('in');
12737 Roo.bootstrap.Popover.alignment = {
12738 'left' : ['r-l', [-10,0], 'right'],
12739 'right' : ['l-r', [10,0], 'left'],
12740 'bottom' : ['t-b', [0,10], 'top'],
12741 'top' : [ 'b-t', [0,-10], 'bottom']
12752 * @class Roo.bootstrap.Progress
12753 * @extends Roo.bootstrap.Component
12754 * Bootstrap Progress class
12755 * @cfg {Boolean} striped striped of the progress bar
12756 * @cfg {Boolean} active animated of the progress bar
12760 * Create a new Progress
12761 * @param {Object} config The config object
12764 Roo.bootstrap.Progress = function(config){
12765 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12768 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12773 getAutoCreate : function(){
12781 cfg.cls += ' progress-striped';
12785 cfg.cls += ' active';
12804 * @class Roo.bootstrap.ProgressBar
12805 * @extends Roo.bootstrap.Component
12806 * Bootstrap ProgressBar class
12807 * @cfg {Number} aria_valuenow aria-value now
12808 * @cfg {Number} aria_valuemin aria-value min
12809 * @cfg {Number} aria_valuemax aria-value max
12810 * @cfg {String} label label for the progress bar
12811 * @cfg {String} panel (success | info | warning | danger )
12812 * @cfg {String} role role of the progress bar
12813 * @cfg {String} sr_only text
12817 * Create a new ProgressBar
12818 * @param {Object} config The config object
12821 Roo.bootstrap.ProgressBar = function(config){
12822 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12825 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12829 aria_valuemax : 100,
12835 getAutoCreate : function()
12840 cls: 'progress-bar',
12841 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12853 cfg.role = this.role;
12856 if(this.aria_valuenow){
12857 cfg['aria-valuenow'] = this.aria_valuenow;
12860 if(this.aria_valuemin){
12861 cfg['aria-valuemin'] = this.aria_valuemin;
12864 if(this.aria_valuemax){
12865 cfg['aria-valuemax'] = this.aria_valuemax;
12868 if(this.label && !this.sr_only){
12869 cfg.html = this.label;
12873 cfg.cls += ' progress-bar-' + this.panel;
12879 update : function(aria_valuenow)
12881 this.aria_valuenow = aria_valuenow;
12883 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12898 * @class Roo.bootstrap.TabPanel
12899 * @extends Roo.bootstrap.Component
12900 * Bootstrap TabPanel class
12901 * @cfg {Boolean} active panel active
12902 * @cfg {String} html panel content
12903 * @cfg {String} tabId tab relate id
12904 * @cfg {String} navId The navbar which triggers show hide
12908 * Create a new TabPanel
12909 * @param {Object} config The config object
12912 Roo.bootstrap.TabPanel = function(config){
12913 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
12917 * Fires when the active status changes
12918 * @param {Roo.bootstrap.TabPanel} this
12919 * @param {Boolean} state the new state
12926 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
12933 getAutoCreate : function(){
12937 html: this.html || ''
12941 cfg.cls += ' active';
12945 cfg.tabId = this.tabId;
12950 onRender : function(ct, position)
12952 // Roo.log("Call onRender: " + this.xtype);
12954 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
12956 if (this.navId && this.tabId) {
12957 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
12959 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
12961 item.on('changed', function(item, state) {
12962 this.setActive(state);
12968 setActive: function(state)
12970 Roo.log("panel - set active " + this.tabId + "=" + state);
12972 this.active = state;
12974 this.el.removeClass('active');
12976 } else if (!this.el.hasClass('active')) {
12977 this.el.addClass('active');
12979 this.fireEvent('changed', this, state);
12996 * @class Roo.bootstrap.DateField
12997 * @extends Roo.bootstrap.Input
12998 * Bootstrap DateField class
12999 * @cfg {Number} weekStart default 0
13000 * @cfg {Number} weekStart default 0
13001 * @cfg {Number} viewMode default empty, (months|years)
13002 * @cfg {Number} minViewMode default empty, (months|years)
13003 * @cfg {Number} startDate default -Infinity
13004 * @cfg {Number} endDate default Infinity
13005 * @cfg {Boolean} todayHighlight default false
13006 * @cfg {Boolean} todayBtn default false
13007 * @cfg {Boolean} calendarWeeks default false
13008 * @cfg {Object} daysOfWeekDisabled default empty
13010 * @cfg {Boolean} keyboardNavigation default true
13011 * @cfg {String} language default en
13014 * Create a new DateField
13015 * @param {Object} config The config object
13018 Roo.bootstrap.DateField = function(config){
13019 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13023 * Fires when this field show.
13024 * @param {Roo.bootstrap.DateField} this
13025 * @param {Mixed} date The date value
13030 * Fires when this field hide.
13031 * @param {Roo.bootstrap.DateField} this
13032 * @param {Mixed} date The date value
13037 * Fires when select a date.
13038 * @param {Roo.bootstrap.DateField} this
13039 * @param {Mixed} date The date value
13045 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
13048 * @cfg {String} format
13049 * The default date format string which can be overriden for localization support. The format must be
13050 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13054 * @cfg {String} altFormats
13055 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13056 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13058 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13066 todayHighlight : false,
13072 keyboardNavigation: true,
13074 calendarWeeks: false,
13076 startDate: -Infinity,
13080 daysOfWeekDisabled: [],
13084 UTCDate: function()
13086 return new Date(Date.UTC.apply(Date, arguments));
13089 UTCToday: function()
13091 var today = new Date();
13092 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13095 getDate: function() {
13096 var d = this.getUTCDate();
13097 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13100 getUTCDate: function() {
13104 setDate: function(d) {
13105 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13108 setUTCDate: function(d) {
13110 this.setValue(this.formatDate(this.date));
13113 onRender: function(ct, position)
13116 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13118 this.language = this.language || 'en';
13119 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13120 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13122 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13123 this.format = this.format || 'm/d/y';
13124 this.isInline = false;
13125 this.isInput = true;
13126 this.component = this.el.select('.add-on', true).first() || false;
13127 this.component = (this.component && this.component.length === 0) ? false : this.component;
13128 this.hasInput = this.component && this.inputEL().length;
13130 if (typeof(this.minViewMode === 'string')) {
13131 switch (this.minViewMode) {
13133 this.minViewMode = 1;
13136 this.minViewMode = 2;
13139 this.minViewMode = 0;
13144 if (typeof(this.viewMode === 'string')) {
13145 switch (this.viewMode) {
13158 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13160 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13162 this.picker().on('mousedown', this.onMousedown, this);
13163 this.picker().on('click', this.onClick, this);
13165 this.picker().addClass('datepicker-dropdown');
13167 this.startViewMode = this.viewMode;
13170 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13171 if(!this.calendarWeeks){
13176 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13177 v.attr('colspan', function(i, val){
13178 return parseInt(val) + 1;
13183 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13185 this.setStartDate(this.startDate);
13186 this.setEndDate(this.endDate);
13188 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13195 if(this.isInline) {
13200 picker : function()
13202 return this.el.select('.datepicker', true).first();
13205 fillDow: function()
13207 var dowCnt = this.weekStart;
13216 if(this.calendarWeeks){
13224 while (dowCnt < this.weekStart + 7) {
13228 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13232 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13235 fillMonths: function()
13238 var months = this.picker().select('>.datepicker-months td', true).first();
13240 months.dom.innerHTML = '';
13246 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13249 months.createChild(month);
13254 update: function(){
13256 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13258 if (this.date < this.startDate) {
13259 this.viewDate = new Date(this.startDate);
13260 } else if (this.date > this.endDate) {
13261 this.viewDate = new Date(this.endDate);
13263 this.viewDate = new Date(this.date);
13270 var d = new Date(this.viewDate),
13271 year = d.getUTCFullYear(),
13272 month = d.getUTCMonth(),
13273 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
13274 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
13275 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
13276 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
13277 currentDate = this.date && this.date.valueOf(),
13278 today = this.UTCToday();
13280 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
13282 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
13284 // this.picker.select('>tfoot th.today').
13285 // .text(dates[this.language].today)
13286 // .toggle(this.todayBtn !== false);
13288 this.updateNavArrows();
13291 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
13293 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
13295 prevMonth.setUTCDate(day);
13297 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
13299 var nextMonth = new Date(prevMonth);
13301 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
13303 nextMonth = nextMonth.valueOf();
13305 var fillMonths = false;
13307 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
13309 while(prevMonth.valueOf() < nextMonth) {
13312 if (prevMonth.getUTCDay() === this.weekStart) {
13314 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
13322 if(this.calendarWeeks){
13323 // ISO 8601: First week contains first thursday.
13324 // ISO also states week starts on Monday, but we can be more abstract here.
13326 // Start of current week: based on weekstart/current date
13327 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
13328 // Thursday of this week
13329 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
13330 // First Thursday of year, year from thursday
13331 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
13332 // Calendar week: ms between thursdays, div ms per day, div 7 days
13333 calWeek = (th - yth) / 864e5 / 7 + 1;
13335 fillMonths.cn.push({
13343 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
13345 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
13348 if (this.todayHighlight &&
13349 prevMonth.getUTCFullYear() == today.getFullYear() &&
13350 prevMonth.getUTCMonth() == today.getMonth() &&
13351 prevMonth.getUTCDate() == today.getDate()) {
13352 clsName += ' today';
13355 if (currentDate && prevMonth.valueOf() === currentDate) {
13356 clsName += ' active';
13359 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
13360 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
13361 clsName += ' disabled';
13364 fillMonths.cn.push({
13366 cls: 'day ' + clsName,
13367 html: prevMonth.getDate()
13370 prevMonth.setDate(prevMonth.getDate()+1);
13373 var currentYear = this.date && this.date.getUTCFullYear();
13374 var currentMonth = this.date && this.date.getUTCMonth();
13376 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
13378 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
13379 v.removeClass('active');
13381 if(currentYear === year && k === currentMonth){
13382 v.addClass('active');
13385 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
13386 v.addClass('disabled');
13392 year = parseInt(year/10, 10) * 10;
13394 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
13396 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
13399 for (var i = -1; i < 11; i++) {
13400 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
13402 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
13410 showMode: function(dir) {
13412 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
13414 Roo.each(this.picker().select('>div',true).elements, function(v){
13415 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13418 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
13423 if(this.isInline) return;
13425 this.picker().removeClass(['bottom', 'top']);
13427 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13429 * place to the top of element!
13433 this.picker().addClass('top');
13434 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13439 this.picker().addClass('bottom');
13441 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13444 parseDate : function(value){
13445 if(!value || value instanceof Date){
13448 var v = Date.parseDate(value, this.format);
13449 if (!v && this.useIso) {
13450 v = Date.parseDate(value, 'Y-m-d');
13452 if(!v && this.altFormats){
13453 if(!this.altFormatsArray){
13454 this.altFormatsArray = this.altFormats.split("|");
13456 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
13457 v = Date.parseDate(value, this.altFormatsArray[i]);
13463 formatDate : function(date, fmt){
13464 return (!date || !(date instanceof Date)) ?
13465 date : date.dateFormat(fmt || this.format);
13468 onFocus : function()
13470 Roo.bootstrap.DateField.superclass.onFocus.call(this);
13474 onBlur : function()
13476 Roo.bootstrap.DateField.superclass.onBlur.call(this);
13482 this.picker().show();
13486 this.fireEvent('show', this, this.date);
13491 if(this.isInline) return;
13492 this.picker().hide();
13493 this.viewMode = this.startViewMode;
13496 this.fireEvent('hide', this, this.date);
13500 onMousedown: function(e){
13501 e.stopPropagation();
13502 e.preventDefault();
13505 keyup: function(e){
13506 Roo.bootstrap.DateField.superclass.keyup.call(this);
13511 setValue: function(v){
13512 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
13514 this.fireEvent('select', this, this.date);
13518 fireKey: function(e){
13519 if (!this.picker().isVisible()){
13520 if (e.keyCode == 27) // allow escape to hide and re-show picker
13524 var dateChanged = false,
13526 newDate, newViewDate;
13530 e.preventDefault();
13534 if (!this.keyboardNavigation) break;
13535 dir = e.keyCode == 37 ? -1 : 1;
13538 newDate = this.moveYear(this.date, dir);
13539 newViewDate = this.moveYear(this.viewDate, dir);
13540 } else if (e.shiftKey){
13541 newDate = this.moveMonth(this.date, dir);
13542 newViewDate = this.moveMonth(this.viewDate, dir);
13544 newDate = new Date(this.date);
13545 newDate.setUTCDate(this.date.getUTCDate() + dir);
13546 newViewDate = new Date(this.viewDate);
13547 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
13549 if (this.dateWithinRange(newDate)){
13550 this.date = newDate;
13551 this.viewDate = newViewDate;
13552 this.setValue(this.formatDate(this.date));
13554 e.preventDefault();
13555 dateChanged = true;
13560 if (!this.keyboardNavigation) break;
13561 dir = e.keyCode == 38 ? -1 : 1;
13563 newDate = this.moveYear(this.date, dir);
13564 newViewDate = this.moveYear(this.viewDate, dir);
13565 } else if (e.shiftKey){
13566 newDate = this.moveMonth(this.date, dir);
13567 newViewDate = this.moveMonth(this.viewDate, dir);
13569 newDate = new Date(this.date);
13570 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
13571 newViewDate = new Date(this.viewDate);
13572 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
13574 if (this.dateWithinRange(newDate)){
13575 this.date = newDate;
13576 this.viewDate = newViewDate;
13577 this.setValue(this.formatDate(this.date));
13579 e.preventDefault();
13580 dateChanged = true;
13584 this.setValue(this.formatDate(this.date));
13586 e.preventDefault();
13589 this.setValue(this.formatDate(this.date));
13596 onClick: function(e) {
13597 e.stopPropagation();
13598 e.preventDefault();
13600 var target = e.getTarget();
13602 if(target.nodeName.toLowerCase() === 'i'){
13603 target = Roo.get(target).dom.parentNode;
13606 var nodeName = target.nodeName;
13607 var className = target.className;
13608 var html = target.innerHTML;
13610 switch(nodeName.toLowerCase()) {
13612 switch(className) {
13618 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
13619 switch(this.viewMode){
13621 this.viewDate = this.moveMonth(this.viewDate, dir);
13625 this.viewDate = this.moveYear(this.viewDate, dir);
13631 var date = new Date();
13632 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
13634 this.setValue(this.formatDate(this.date));
13640 if (className.indexOf('disabled') === -1) {
13641 this.viewDate.setUTCDate(1);
13642 if (className.indexOf('month') !== -1) {
13643 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
13645 var year = parseInt(html, 10) || 0;
13646 this.viewDate.setUTCFullYear(year);
13655 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
13656 var day = parseInt(html, 10) || 1;
13657 var year = this.viewDate.getUTCFullYear(),
13658 month = this.viewDate.getUTCMonth();
13660 if (className.indexOf('old') !== -1) {
13667 } else if (className.indexOf('new') !== -1) {
13675 this.date = this.UTCDate(year, month, day,0,0,0,0);
13676 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
13678 this.setValue(this.formatDate(this.date));
13685 setStartDate: function(startDate){
13686 this.startDate = startDate || -Infinity;
13687 if (this.startDate !== -Infinity) {
13688 this.startDate = this.parseDate(this.startDate);
13691 this.updateNavArrows();
13694 setEndDate: function(endDate){
13695 this.endDate = endDate || Infinity;
13696 if (this.endDate !== Infinity) {
13697 this.endDate = this.parseDate(this.endDate);
13700 this.updateNavArrows();
13703 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13704 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13705 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13706 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13708 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13709 return parseInt(d, 10);
13712 this.updateNavArrows();
13715 updateNavArrows: function() {
13716 var d = new Date(this.viewDate),
13717 year = d.getUTCFullYear(),
13718 month = d.getUTCMonth();
13720 Roo.each(this.picker().select('.prev', true).elements, function(v){
13722 switch (this.viewMode) {
13725 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13731 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13738 Roo.each(this.picker().select('.next', true).elements, function(v){
13740 switch (this.viewMode) {
13743 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13749 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13757 moveMonth: function(date, dir){
13758 if (!dir) return date;
13759 var new_date = new Date(date.valueOf()),
13760 day = new_date.getUTCDate(),
13761 month = new_date.getUTCMonth(),
13762 mag = Math.abs(dir),
13764 dir = dir > 0 ? 1 : -1;
13767 // If going back one month, make sure month is not current month
13768 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13770 return new_date.getUTCMonth() == month;
13772 // If going forward one month, make sure month is as expected
13773 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13775 return new_date.getUTCMonth() != new_month;
13777 new_month = month + dir;
13778 new_date.setUTCMonth(new_month);
13779 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13780 if (new_month < 0 || new_month > 11)
13781 new_month = (new_month + 12) % 12;
13783 // For magnitudes >1, move one month at a time...
13784 for (var i=0; i<mag; i++)
13785 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13786 new_date = this.moveMonth(new_date, dir);
13787 // ...then reset the day, keeping it in the new month
13788 new_month = new_date.getUTCMonth();
13789 new_date.setUTCDate(day);
13791 return new_month != new_date.getUTCMonth();
13794 // Common date-resetting loop -- if date is beyond end of month, make it
13797 new_date.setUTCDate(--day);
13798 new_date.setUTCMonth(new_month);
13803 moveYear: function(date, dir){
13804 return this.moveMonth(date, dir*12);
13807 dateWithinRange: function(date){
13808 return date >= this.startDate && date <= this.endDate;
13812 remove: function() {
13813 this.picker().remove();
13818 Roo.apply(Roo.bootstrap.DateField, {
13829 html: '<i class="icon-arrow-left"/>'
13839 html: '<i class="icon-arrow-right"/>'
13881 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13882 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13883 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13884 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13885 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13898 navFnc: 'FullYear',
13903 navFnc: 'FullYear',
13908 Roo.apply(Roo.bootstrap.DateField, {
13912 cls: 'datepicker dropdown-menu',
13916 cls: 'datepicker-days',
13920 cls: 'table-condensed',
13922 Roo.bootstrap.DateField.head,
13926 Roo.bootstrap.DateField.footer
13933 cls: 'datepicker-months',
13937 cls: 'table-condensed',
13939 Roo.bootstrap.DateField.head,
13940 Roo.bootstrap.DateField.content,
13941 Roo.bootstrap.DateField.footer
13948 cls: 'datepicker-years',
13952 cls: 'table-condensed',
13954 Roo.bootstrap.DateField.head,
13955 Roo.bootstrap.DateField.content,
13956 Roo.bootstrap.DateField.footer
13975 * @class Roo.bootstrap.TimeField
13976 * @extends Roo.bootstrap.Input
13977 * Bootstrap DateField class
13981 * Create a new TimeField
13982 * @param {Object} config The config object
13985 Roo.bootstrap.TimeField = function(config){
13986 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
13990 * Fires when this field show.
13991 * @param {Roo.bootstrap.DateField} this
13992 * @param {Mixed} date The date value
13997 * Fires when this field hide.
13998 * @param {Roo.bootstrap.DateField} this
13999 * @param {Mixed} date The date value
14004 * Fires when select a date.
14005 * @param {Roo.bootstrap.DateField} this
14006 * @param {Mixed} date The date value
14012 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
14015 * @cfg {String} format
14016 * The default time format string which can be overriden for localization support. The format must be
14017 * valid according to {@link Date#parseDate} (defaults to 'H:i').
14021 onRender: function(ct, position)
14024 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14026 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14028 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14030 this.pop = this.picker().select('>.datepicker-time',true).first();
14031 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
14033 this.picker().on('mousedown', this.onMousedown, this);
14034 this.picker().on('click', this.onClick, this);
14036 this.picker().addClass('datepicker-dropdown');
14041 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14042 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14043 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14044 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14045 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14046 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14050 fireKey: function(e){
14051 if (!this.picker().isVisible()){
14052 if (e.keyCode == 27) // allow escape to hide and re-show picker
14057 e.preventDefault();
14065 this.onTogglePeriod();
14068 this.onIncrementMinutes();
14071 this.onDecrementMinutes();
14080 onClick: function(e) {
14081 e.stopPropagation();
14082 e.preventDefault();
14085 picker : function()
14087 return this.el.select('.datepicker', true).first();
14090 fillTime: function()
14092 var time = this.pop.select('tbody', true).first();
14094 time.dom.innerHTML = '';
14109 cls: 'hours-up glyphicon glyphicon-chevron-up'
14129 cls: 'minutes-up glyphicon glyphicon-chevron-up'
14150 cls: 'timepicker-hour',
14165 cls: 'timepicker-minute',
14180 cls: 'btn btn-primary period',
14202 cls: 'hours-down glyphicon glyphicon-chevron-down'
14222 cls: 'minutes-down glyphicon glyphicon-chevron-down'
14240 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
14247 var hours = this.time.getHours();
14248 var minutes = this.time.getMinutes();
14261 hours = hours - 12;
14265 hours = '0' + hours;
14269 minutes = '0' + minutes;
14272 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
14273 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
14274 this.pop.select('button', true).first().dom.innerHTML = period;
14280 this.picker().removeClass(['bottom', 'top']);
14282 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14284 * place to the top of element!
14288 this.picker().addClass('top');
14289 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14294 this.picker().addClass('bottom');
14296 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14299 onFocus : function()
14301 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
14305 onBlur : function()
14307 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
14313 this.picker().show();
14318 this.fireEvent('show', this, this.date);
14323 this.picker().hide();
14326 this.fireEvent('hide', this, this.date);
14329 setTime : function()
14332 this.setValue(this.time.format(this.format));
14334 this.fireEvent('select', this, this.date);
14339 onMousedown: function(e){
14340 e.stopPropagation();
14341 e.preventDefault();
14344 onIncrementHours: function()
14346 Roo.log('onIncrementHours');
14347 this.time = this.time.add(Date.HOUR, 1);
14352 onDecrementHours: function()
14354 Roo.log('onDecrementHours');
14355 this.time = this.time.add(Date.HOUR, -1);
14359 onIncrementMinutes: function()
14361 Roo.log('onIncrementMinutes');
14362 this.time = this.time.add(Date.MINUTE, 1);
14366 onDecrementMinutes: function()
14368 Roo.log('onDecrementMinutes');
14369 this.time = this.time.add(Date.MINUTE, -1);
14373 onTogglePeriod: function()
14375 Roo.log('onTogglePeriod');
14376 this.time = this.time.add(Date.HOUR, 12);
14383 Roo.apply(Roo.bootstrap.TimeField, {
14413 cls: 'btn btn-info ok',
14425 Roo.apply(Roo.bootstrap.TimeField, {
14429 cls: 'datepicker dropdown-menu',
14433 cls: 'datepicker-time',
14437 cls: 'table-condensed',
14439 Roo.bootstrap.TimeField.content,
14440 Roo.bootstrap.TimeField.footer
14459 * @class Roo.bootstrap.CheckBox
14460 * @extends Roo.bootstrap.Input
14461 * Bootstrap CheckBox class
14463 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
14464 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
14465 * @cfg {String} boxLabel The text that appears beside the checkbox
14466 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
14467 * @cfg {Boolean} checked initnal the element
14471 * Create a new CheckBox
14472 * @param {Object} config The config object
14475 Roo.bootstrap.CheckBox = function(config){
14476 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
14481 * Fires when the element is checked or unchecked.
14482 * @param {Roo.bootstrap.CheckBox} this This input
14483 * @param {Boolean} checked The new checked value
14489 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
14491 inputType: 'checkbox',
14498 getAutoCreate : function()
14500 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14506 cfg.cls = 'form-group checkbox' //input-group
14514 type : this.inputType,
14515 value : (!this.checked) ? this.valueOff : this.inputValue,
14516 cls : 'roo-checkbox', //'form-box',
14517 placeholder : this.placeholder || ''
14521 if (this.weight) { // Validity check?
14522 cfg.cls += " checkbox-" + this.weight;
14525 if (this.disabled) {
14526 input.disabled=true;
14530 input.checked = this.checked;
14534 input.name = this.name;
14538 input.cls += ' input-' + this.size;
14542 ['xs','sm','md','lg'].map(function(size){
14543 if (settings[size]) {
14544 cfg.cls += ' col-' + size + '-' + settings[size];
14550 var inputblock = input;
14555 if (this.before || this.after) {
14558 cls : 'input-group',
14562 inputblock.cn.push({
14564 cls : 'input-group-addon',
14568 inputblock.cn.push(input);
14570 inputblock.cn.push({
14572 cls : 'input-group-addon',
14579 if (align ==='left' && this.fieldLabel.length) {
14580 Roo.log("left and has label");
14586 cls : 'control-label col-md-' + this.labelWidth,
14587 html : this.fieldLabel
14591 cls : "col-md-" + (12 - this.labelWidth),
14598 } else if ( this.fieldLabel.length) {
14603 tag: this.boxLabel ? 'span' : 'label',
14605 cls: 'control-label box-input-label',
14606 //cls : 'input-group-addon',
14607 html : this.fieldLabel
14617 Roo.log(" no label && no align");
14618 cfg.cn = [ inputblock ] ;
14627 html: this.boxLabel
14639 * return the real input element.
14641 inputEl: function ()
14643 return this.el.select('input.roo-checkbox',true).first();
14648 return this.el.select('label.control-label',true).first();
14651 initEvents : function()
14653 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
14655 this.inputEl().on('click', this.onClick, this);
14659 onClick : function()
14661 this.setChecked(!this.checked);
14664 setChecked : function(state,suppressEvent)
14666 this.checked = state;
14668 this.inputEl().dom.checked = state;
14670 if(suppressEvent !== true){
14671 this.fireEvent('check', this, state);
14674 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14678 setValue : function(v,suppressEvent)
14680 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14694 * @class Roo.bootstrap.Radio
14695 * @extends Roo.bootstrap.CheckBox
14696 * Bootstrap Radio class
14699 * Create a new Radio
14700 * @param {Object} config The config object
14703 Roo.bootstrap.Radio = function(config){
14704 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14708 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14710 inputType: 'radio',
14714 getAutoCreate : function()
14716 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14722 cfg.cls = 'form-group radio' //input-group
14727 type : this.inputType,
14728 value : (!this.checked) ? this.valueOff : this.inputValue,
14730 placeholder : this.placeholder || ''
14733 if (this.weight) { // Validity check?
14734 cfg.cls += " radio-" + this.weight;
14736 if (this.disabled) {
14737 input.disabled=true;
14741 input.checked = this.checked;
14745 input.name = this.name;
14749 input.cls += ' input-' + this.size;
14753 ['xs','sm','md','lg'].map(function(size){
14754 if (settings[size]) {
14755 cfg.cls += ' col-' + size + '-' + settings[size];
14759 var inputblock = input;
14761 if (this.before || this.after) {
14764 cls : 'input-group',
14768 inputblock.cn.push({
14770 cls : 'input-group-addon',
14774 inputblock.cn.push(input);
14776 inputblock.cn.push({
14778 cls : 'input-group-addon',
14785 if (align ==='left' && this.fieldLabel.length) {
14786 Roo.log("left and has label");
14792 cls : 'control-label col-md-' + this.labelWidth,
14793 html : this.fieldLabel
14797 cls : "col-md-" + (12 - this.labelWidth),
14804 } else if ( this.fieldLabel.length) {
14811 cls: 'control-label box-input-label',
14812 //cls : 'input-group-addon',
14813 html : this.fieldLabel
14823 Roo.log(" no label && no align");
14838 html: this.boxLabel
14845 inputEl: function ()
14847 return this.el.select('input.roo-radio',true).first();
14849 onClick : function()
14851 this.setChecked(true);
14854 setChecked : function(state,suppressEvent)
14857 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14858 v.dom.checked = false;
14862 this.checked = state;
14863 this.inputEl().dom.checked = state;
14865 if(suppressEvent !== true){
14866 this.fireEvent('check', this, state);
14869 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14873 getGroupValue : function()
14876 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14877 if(v.dom.checked == true){
14878 value = v.dom.value;
14886 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
14887 * @return {Mixed} value The field value
14889 getValue : function(){
14890 return this.getGroupValue();
14896 //<script type="text/javascript">
14899 * Based Ext JS Library 1.1.1
14900 * Copyright(c) 2006-2007, Ext JS, LLC.
14906 * @class Roo.HtmlEditorCore
14907 * @extends Roo.Component
14908 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
14910 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
14913 Roo.HtmlEditorCore = function(config){
14916 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
14919 * @event initialize
14920 * Fires when the editor is fully initialized (including the iframe)
14921 * @param {Roo.HtmlEditorCore} this
14926 * Fires when the editor is first receives the focus. Any insertion must wait
14927 * until after this event.
14928 * @param {Roo.HtmlEditorCore} this
14932 * @event beforesync
14933 * Fires before the textarea is updated with content from the editor iframe. Return false
14934 * to cancel the sync.
14935 * @param {Roo.HtmlEditorCore} this
14936 * @param {String} html
14940 * @event beforepush
14941 * Fires before the iframe editor is updated with content from the textarea. Return false
14942 * to cancel the push.
14943 * @param {Roo.HtmlEditorCore} this
14944 * @param {String} html
14949 * Fires when the textarea is updated with content from the editor iframe.
14950 * @param {Roo.HtmlEditorCore} this
14951 * @param {String} html
14956 * Fires when the iframe editor is updated with content from the textarea.
14957 * @param {Roo.HtmlEditorCore} this
14958 * @param {String} html
14963 * @event editorevent
14964 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14965 * @param {Roo.HtmlEditorCore} this
14973 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
14977 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
14983 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14988 * @cfg {Number} height (in pixels)
14992 * @cfg {Number} width (in pixels)
14997 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15000 stylesheets: false,
15005 // private properties
15006 validationEvent : false,
15008 initialized : false,
15010 sourceEditMode : false,
15011 onFocus : Roo.emptyFn,
15013 hideMode:'offsets',
15021 * Protected method that will not generally be called directly. It
15022 * is called when the editor initializes the iframe with HTML contents. Override this method if you
15023 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15025 getDocMarkup : function(){
15028 Roo.log(this.stylesheets);
15030 // inherit styels from page...??
15031 if (this.stylesheets === false) {
15033 Roo.get(document.head).select('style').each(function(node) {
15034 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15037 Roo.get(document.head).select('link').each(function(node) {
15038 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15041 } else if (!this.stylesheets.length) {
15043 st = '<style type="text/css">' +
15044 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15047 Roo.each(this.stylesheets, function(s) {
15048 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15053 st += '<style type="text/css">' +
15054 'IMG { cursor: pointer } ' +
15058 return '<html><head>' + st +
15059 //<style type="text/css">' +
15060 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15062 ' </head><body class="roo-htmleditor-body"></body></html>';
15066 onRender : function(ct, position)
15069 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15070 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15073 this.el.dom.style.border = '0 none';
15074 this.el.dom.setAttribute('tabIndex', -1);
15075 this.el.addClass('x-hidden hide');
15079 if(Roo.isIE){ // fix IE 1px bogus margin
15080 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15084 this.frameId = Roo.id();
15088 var iframe = this.owner.wrap.createChild({
15090 cls: 'form-control', // bootstrap..
15092 name: this.frameId,
15093 frameBorder : 'no',
15094 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
15099 this.iframe = iframe.dom;
15101 this.assignDocWin();
15103 this.doc.designMode = 'on';
15106 this.doc.write(this.getDocMarkup());
15110 var task = { // must defer to wait for browser to be ready
15112 //console.log("run task?" + this.doc.readyState);
15113 this.assignDocWin();
15114 if(this.doc.body || this.doc.readyState == 'complete'){
15116 this.doc.designMode="on";
15120 Roo.TaskMgr.stop(task);
15121 this.initEditor.defer(10, this);
15128 Roo.TaskMgr.start(task);
15135 onResize : function(w, h)
15137 Roo.log('resize: ' +w + ',' + h );
15138 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15142 if(typeof w == 'number'){
15144 this.iframe.style.width = w + 'px';
15146 if(typeof h == 'number'){
15148 this.iframe.style.height = h + 'px';
15150 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15157 * Toggles the editor between standard and source edit mode.
15158 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15160 toggleSourceEdit : function(sourceEditMode){
15162 this.sourceEditMode = sourceEditMode === true;
15164 if(this.sourceEditMode){
15166 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
15169 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15170 //this.iframe.className = '';
15173 //this.setSize(this.owner.wrap.getSize());
15174 //this.fireEvent('editmodechange', this, this.sourceEditMode);
15181 * Protected method that will not generally be called directly. If you need/want
15182 * custom HTML cleanup, this is the method you should override.
15183 * @param {String} html The HTML to be cleaned
15184 * return {String} The cleaned HTML
15186 cleanHtml : function(html){
15187 html = String(html);
15188 if(html.length > 5){
15189 if(Roo.isSafari){ // strip safari nonsense
15190 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15193 if(html == ' '){
15200 * HTML Editor -> Textarea
15201 * Protected method that will not generally be called directly. Syncs the contents
15202 * of the editor iframe with the textarea.
15204 syncValue : function(){
15205 if(this.initialized){
15206 var bd = (this.doc.body || this.doc.documentElement);
15207 //this.cleanUpPaste(); -- this is done else where and causes havoc..
15208 var html = bd.innerHTML;
15210 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
15211 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
15213 html = '<div style="'+m[0]+'">' + html + '</div>';
15216 html = this.cleanHtml(html);
15217 // fix up the special chars.. normaly like back quotes in word...
15218 // however we do not want to do this with chinese..
15219 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
15220 var cc = b.charCodeAt();
15222 (cc >= 0x4E00 && cc < 0xA000 ) ||
15223 (cc >= 0x3400 && cc < 0x4E00 ) ||
15224 (cc >= 0xf900 && cc < 0xfb00 )
15230 if(this.owner.fireEvent('beforesync', this, html) !== false){
15231 this.el.dom.value = html;
15232 this.owner.fireEvent('sync', this, html);
15238 * Protected method that will not generally be called directly. Pushes the value of the textarea
15239 * into the iframe editor.
15241 pushValue : function(){
15242 if(this.initialized){
15243 var v = this.el.dom.value.trim();
15245 // if(v.length < 1){
15249 if(this.owner.fireEvent('beforepush', this, v) !== false){
15250 var d = (this.doc.body || this.doc.documentElement);
15252 this.cleanUpPaste();
15253 this.el.dom.value = d.innerHTML;
15254 this.owner.fireEvent('push', this, v);
15260 deferFocus : function(){
15261 this.focus.defer(10, this);
15265 focus : function(){
15266 if(this.win && !this.sourceEditMode){
15273 assignDocWin: function()
15275 var iframe = this.iframe;
15278 this.doc = iframe.contentWindow.document;
15279 this.win = iframe.contentWindow;
15281 if (!Roo.get(this.frameId)) {
15284 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
15285 this.win = Roo.get(this.frameId).dom.contentWindow;
15290 initEditor : function(){
15291 //console.log("INIT EDITOR");
15292 this.assignDocWin();
15296 this.doc.designMode="on";
15298 this.doc.write(this.getDocMarkup());
15301 var dbody = (this.doc.body || this.doc.documentElement);
15302 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
15303 // this copies styles from the containing element into thsi one..
15304 // not sure why we need all of this..
15305 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
15307 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
15308 //ss['background-attachment'] = 'fixed'; // w3c
15309 dbody.bgProperties = 'fixed'; // ie
15310 //Roo.DomHelper.applyStyles(dbody, ss);
15311 Roo.EventManager.on(this.doc, {
15312 //'mousedown': this.onEditorEvent,
15313 'mouseup': this.onEditorEvent,
15314 'dblclick': this.onEditorEvent,
15315 'click': this.onEditorEvent,
15316 'keyup': this.onEditorEvent,
15321 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
15323 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
15324 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
15326 this.initialized = true;
15328 this.owner.fireEvent('initialize', this);
15333 onDestroy : function(){
15339 //for (var i =0; i < this.toolbars.length;i++) {
15340 // // fixme - ask toolbars for heights?
15341 // this.toolbars[i].onDestroy();
15344 //this.wrap.dom.innerHTML = '';
15345 //this.wrap.remove();
15350 onFirstFocus : function(){
15352 this.assignDocWin();
15355 this.activated = true;
15358 if(Roo.isGecko){ // prevent silly gecko errors
15360 var s = this.win.getSelection();
15361 if(!s.focusNode || s.focusNode.nodeType != 3){
15362 var r = s.getRangeAt(0);
15363 r.selectNodeContents((this.doc.body || this.doc.documentElement));
15368 this.execCmd('useCSS', true);
15369 this.execCmd('styleWithCSS', false);
15372 this.owner.fireEvent('activate', this);
15376 adjustFont: function(btn){
15377 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
15378 //if(Roo.isSafari){ // safari
15381 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
15382 if(Roo.isSafari){ // safari
15383 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
15384 v = (v < 10) ? 10 : v;
15385 v = (v > 48) ? 48 : v;
15386 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
15391 v = Math.max(1, v+adjust);
15393 this.execCmd('FontSize', v );
15396 onEditorEvent : function(e){
15397 this.owner.fireEvent('editorevent', this, e);
15398 // this.updateToolbar();
15399 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
15402 insertTag : function(tg)
15404 // could be a bit smarter... -> wrap the current selected tRoo..
15405 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
15407 range = this.createRange(this.getSelection());
15408 var wrappingNode = this.doc.createElement(tg.toLowerCase());
15409 wrappingNode.appendChild(range.extractContents());
15410 range.insertNode(wrappingNode);
15417 this.execCmd("formatblock", tg);
15421 insertText : function(txt)
15425 var range = this.createRange();
15426 range.deleteContents();
15427 //alert(Sender.getAttribute('label'));
15429 range.insertNode(this.doc.createTextNode(txt));
15435 * Executes a Midas editor command on the editor document and performs necessary focus and
15436 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
15437 * @param {String} cmd The Midas command
15438 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
15440 relayCmd : function(cmd, value){
15442 this.execCmd(cmd, value);
15443 this.owner.fireEvent('editorevent', this);
15444 //this.updateToolbar();
15445 this.owner.deferFocus();
15449 * Executes a Midas editor command directly on the editor document.
15450 * For visual commands, you should use {@link #relayCmd} instead.
15451 * <b>This should only be called after the editor is initialized.</b>
15452 * @param {String} cmd The Midas command
15453 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
15455 execCmd : function(cmd, value){
15456 this.doc.execCommand(cmd, false, value === undefined ? null : value);
15463 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
15465 * @param {String} text | dom node..
15467 insertAtCursor : function(text)
15472 if(!this.activated){
15478 var r = this.doc.selection.createRange();
15489 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
15493 // from jquery ui (MIT licenced)
15495 var win = this.win;
15497 if (win.getSelection && win.getSelection().getRangeAt) {
15498 range = win.getSelection().getRangeAt(0);
15499 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
15500 range.insertNode(node);
15501 } else if (win.document.selection && win.document.selection.createRange) {
15502 // no firefox support
15503 var txt = typeof(text) == 'string' ? text : text.outerHTML;
15504 win.document.selection.createRange().pasteHTML(txt);
15506 // no firefox support
15507 var txt = typeof(text) == 'string' ? text : text.outerHTML;
15508 this.execCmd('InsertHTML', txt);
15517 mozKeyPress : function(e){
15519 var c = e.getCharCode(), cmd;
15522 c = String.fromCharCode(c).toLowerCase();
15536 this.cleanUpPaste.defer(100, this);
15544 e.preventDefault();
15552 fixKeys : function(){ // load time branching for fastest keydown performance
15554 return function(e){
15555 var k = e.getKey(), r;
15558 r = this.doc.selection.createRange();
15561 r.pasteHTML('    ');
15568 r = this.doc.selection.createRange();
15570 var target = r.parentElement();
15571 if(!target || target.tagName.toLowerCase() != 'li'){
15573 r.pasteHTML('<br />');
15579 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15580 this.cleanUpPaste.defer(100, this);
15586 }else if(Roo.isOpera){
15587 return function(e){
15588 var k = e.getKey();
15592 this.execCmd('InsertHTML','    ');
15595 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15596 this.cleanUpPaste.defer(100, this);
15601 }else if(Roo.isSafari){
15602 return function(e){
15603 var k = e.getKey();
15607 this.execCmd('InsertText','\t');
15611 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15612 this.cleanUpPaste.defer(100, this);
15620 getAllAncestors: function()
15622 var p = this.getSelectedNode();
15625 a.push(p); // push blank onto stack..
15626 p = this.getParentElement();
15630 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
15634 a.push(this.doc.body);
15638 lastSelNode : false,
15641 getSelection : function()
15643 this.assignDocWin();
15644 return Roo.isIE ? this.doc.selection : this.win.getSelection();
15647 getSelectedNode: function()
15649 // this may only work on Gecko!!!
15651 // should we cache this!!!!
15656 var range = this.createRange(this.getSelection()).cloneRange();
15659 var parent = range.parentElement();
15661 var testRange = range.duplicate();
15662 testRange.moveToElementText(parent);
15663 if (testRange.inRange(range)) {
15666 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
15669 parent = parent.parentElement;
15674 // is ancestor a text element.
15675 var ac = range.commonAncestorContainer;
15676 if (ac.nodeType == 3) {
15677 ac = ac.parentNode;
15680 var ar = ac.childNodes;
15683 var other_nodes = [];
15684 var has_other_nodes = false;
15685 for (var i=0;i<ar.length;i++) {
15686 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
15689 // fullly contained node.
15691 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15696 // probably selected..
15697 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15698 other_nodes.push(ar[i]);
15702 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15707 has_other_nodes = true;
15709 if (!nodes.length && other_nodes.length) {
15710 nodes= other_nodes;
15712 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15718 createRange: function(sel)
15720 // this has strange effects when using with
15721 // top toolbar - not sure if it's a great idea.
15722 //this.editor.contentWindow.focus();
15723 if (typeof sel != "undefined") {
15725 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15727 return this.doc.createRange();
15730 return this.doc.createRange();
15733 getParentElement: function()
15736 this.assignDocWin();
15737 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15739 var range = this.createRange(sel);
15742 var p = range.commonAncestorContainer;
15743 while (p.nodeType == 3) { // text node
15754 * Range intersection.. the hard stuff...
15758 * [ -- selected range --- ]
15762 * if end is before start or hits it. fail.
15763 * if start is after end or hits it fail.
15765 * if either hits (but other is outside. - then it's not
15771 // @see http://www.thismuchiknow.co.uk/?p=64.
15772 rangeIntersectsNode : function(range, node)
15774 var nodeRange = node.ownerDocument.createRange();
15776 nodeRange.selectNode(node);
15778 nodeRange.selectNodeContents(node);
15781 var rangeStartRange = range.cloneRange();
15782 rangeStartRange.collapse(true);
15784 var rangeEndRange = range.cloneRange();
15785 rangeEndRange.collapse(false);
15787 var nodeStartRange = nodeRange.cloneRange();
15788 nodeStartRange.collapse(true);
15790 var nodeEndRange = nodeRange.cloneRange();
15791 nodeEndRange.collapse(false);
15793 return rangeStartRange.compareBoundaryPoints(
15794 Range.START_TO_START, nodeEndRange) == -1 &&
15795 rangeEndRange.compareBoundaryPoints(
15796 Range.START_TO_START, nodeStartRange) == 1;
15800 rangeCompareNode : function(range, node)
15802 var nodeRange = node.ownerDocument.createRange();
15804 nodeRange.selectNode(node);
15806 nodeRange.selectNodeContents(node);
15810 range.collapse(true);
15812 nodeRange.collapse(true);
15814 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15815 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15817 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15819 var nodeIsBefore = ss == 1;
15820 var nodeIsAfter = ee == -1;
15822 if (nodeIsBefore && nodeIsAfter)
15824 if (!nodeIsBefore && nodeIsAfter)
15825 return 1; //right trailed.
15827 if (nodeIsBefore && !nodeIsAfter)
15828 return 2; // left trailed.
15833 // private? - in a new class?
15834 cleanUpPaste : function()
15836 // cleans up the whole document..
15837 Roo.log('cleanuppaste');
15839 this.cleanUpChildren(this.doc.body);
15840 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15841 if (clean != this.doc.body.innerHTML) {
15842 this.doc.body.innerHTML = clean;
15847 cleanWordChars : function(input) {// change the chars to hex code
15848 var he = Roo.HtmlEditorCore;
15850 var output = input;
15851 Roo.each(he.swapCodes, function(sw) {
15852 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15854 output = output.replace(swapper, sw[1]);
15861 cleanUpChildren : function (n)
15863 if (!n.childNodes.length) {
15866 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15867 this.cleanUpChild(n.childNodes[i]);
15874 cleanUpChild : function (node)
15877 //console.log(node);
15878 if (node.nodeName == "#text") {
15879 // clean up silly Windows -- stuff?
15882 if (node.nodeName == "#comment") {
15883 node.parentNode.removeChild(node);
15884 // clean up silly Windows -- stuff?
15888 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
15890 node.parentNode.removeChild(node);
15895 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
15897 // remove <a name=....> as rendering on yahoo mailer is borked with this.
15898 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
15900 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
15901 // remove_keep_children = true;
15904 if (remove_keep_children) {
15905 this.cleanUpChildren(node);
15906 // inserts everything just before this node...
15907 while (node.childNodes.length) {
15908 var cn = node.childNodes[0];
15909 node.removeChild(cn);
15910 node.parentNode.insertBefore(cn, node);
15912 node.parentNode.removeChild(node);
15916 if (!node.attributes || !node.attributes.length) {
15917 this.cleanUpChildren(node);
15921 function cleanAttr(n,v)
15924 if (v.match(/^\./) || v.match(/^\//)) {
15927 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
15930 if (v.match(/^#/)) {
15933 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
15934 node.removeAttribute(n);
15938 function cleanStyle(n,v)
15940 if (v.match(/expression/)) { //XSS?? should we even bother..
15941 node.removeAttribute(n);
15944 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
15945 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
15948 var parts = v.split(/;/);
15951 Roo.each(parts, function(p) {
15952 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
15956 var l = p.split(':').shift().replace(/\s+/g,'');
15957 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
15959 if ( cblack.indexOf(l) > -1) {
15960 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15961 //node.removeAttribute(n);
15965 // only allow 'c whitelisted system attributes'
15966 if ( cwhite.length && cwhite.indexOf(l) < 0) {
15967 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15968 //node.removeAttribute(n);
15978 if (clean.length) {
15979 node.setAttribute(n, clean.join(';'));
15981 node.removeAttribute(n);
15987 for (var i = node.attributes.length-1; i > -1 ; i--) {
15988 var a = node.attributes[i];
15991 if (a.name.toLowerCase().substr(0,2)=='on') {
15992 node.removeAttribute(a.name);
15995 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
15996 node.removeAttribute(a.name);
15999 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16000 cleanAttr(a.name,a.value); // fixme..
16003 if (a.name == 'style') {
16004 cleanStyle(a.name,a.value);
16007 /// clean up MS crap..
16008 // tecnically this should be a list of valid class'es..
16011 if (a.name == 'class') {
16012 if (a.value.match(/^Mso/)) {
16013 node.className = '';
16016 if (a.value.match(/body/)) {
16017 node.className = '';
16028 this.cleanUpChildren(node);
16033 * Clean up MS wordisms...
16035 cleanWord : function(node)
16038 var cleanWordChildren = function()
16040 if (!node.childNodes.length) {
16043 for (var i = node.childNodes.length-1; i > -1 ; i--) {
16044 _t.cleanWord(node.childNodes[i]);
16050 this.cleanWord(this.doc.body);
16053 if (node.nodeName == "#text") {
16054 // clean up silly Windows -- stuff?
16057 if (node.nodeName == "#comment") {
16058 node.parentNode.removeChild(node);
16059 // clean up silly Windows -- stuff?
16063 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16064 node.parentNode.removeChild(node);
16068 // remove - but keep children..
16069 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16070 while (node.childNodes.length) {
16071 var cn = node.childNodes[0];
16072 node.removeChild(cn);
16073 node.parentNode.insertBefore(cn, node);
16075 node.parentNode.removeChild(node);
16076 cleanWordChildren();
16080 if (node.className.length) {
16082 var cn = node.className.split(/\W+/);
16084 Roo.each(cn, function(cls) {
16085 if (cls.match(/Mso[a-zA-Z]+/)) {
16090 node.className = cna.length ? cna.join(' ') : '';
16092 node.removeAttribute("class");
16096 if (node.hasAttribute("lang")) {
16097 node.removeAttribute("lang");
16100 if (node.hasAttribute("style")) {
16102 var styles = node.getAttribute("style").split(";");
16104 Roo.each(styles, function(s) {
16105 if (!s.match(/:/)) {
16108 var kv = s.split(":");
16109 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16112 // what ever is left... we allow.
16115 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16116 if (!nstyle.length) {
16117 node.removeAttribute('style');
16121 cleanWordChildren();
16125 domToHTML : function(currentElement, depth, nopadtext) {
16127 depth = depth || 0;
16128 nopadtext = nopadtext || false;
16130 if (!currentElement) {
16131 return this.domToHTML(this.doc.body);
16134 //Roo.log(currentElement);
16136 var allText = false;
16137 var nodeName = currentElement.nodeName;
16138 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16140 if (nodeName == '#text') {
16141 return currentElement.nodeValue;
16146 if (nodeName != 'BODY') {
16149 // Prints the node tagName, such as <A>, <IMG>, etc
16152 for(i = 0; i < currentElement.attributes.length;i++) {
16154 var aname = currentElement.attributes.item(i).name;
16155 if (!currentElement.attributes.item(i).value.length) {
16158 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16161 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16170 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16173 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16178 // Traverse the tree
16180 var currentElementChild = currentElement.childNodes.item(i);
16181 var allText = true;
16182 var innerHTML = '';
16184 while (currentElementChild) {
16185 // Formatting code (indent the tree so it looks nice on the screen)
16186 var nopad = nopadtext;
16187 if (lastnode == 'SPAN') {
16191 if (currentElementChild.nodeName == '#text') {
16192 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16193 if (!nopad && toadd.length > 80) {
16194 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
16196 innerHTML += toadd;
16199 currentElementChild = currentElement.childNodes.item(i);
16205 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
16207 // Recursively traverse the tree structure of the child node
16208 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
16209 lastnode = currentElementChild.nodeName;
16211 currentElementChild=currentElement.childNodes.item(i);
16217 // The remaining code is mostly for formatting the tree
16218 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
16223 ret+= "</"+tagName+">";
16229 // hide stuff that is not compatible
16243 * @event specialkey
16247 * @cfg {String} fieldClass @hide
16250 * @cfg {String} focusClass @hide
16253 * @cfg {String} autoCreate @hide
16256 * @cfg {String} inputType @hide
16259 * @cfg {String} invalidClass @hide
16262 * @cfg {String} invalidText @hide
16265 * @cfg {String} msgFx @hide
16268 * @cfg {String} validateOnBlur @hide
16272 Roo.HtmlEditorCore.white = [
16273 'area', 'br', 'img', 'input', 'hr', 'wbr',
16275 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
16276 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
16277 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
16278 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
16279 'table', 'ul', 'xmp',
16281 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
16284 'dir', 'menu', 'ol', 'ul', 'dl',
16290 Roo.HtmlEditorCore.black = [
16291 // 'embed', 'object', // enable - backend responsiblity to clean thiese
16293 'base', 'basefont', 'bgsound', 'blink', 'body',
16294 'frame', 'frameset', 'head', 'html', 'ilayer',
16295 'iframe', 'layer', 'link', 'meta', 'object',
16296 'script', 'style' ,'title', 'xml' // clean later..
16298 Roo.HtmlEditorCore.clean = [
16299 'script', 'style', 'title', 'xml'
16301 Roo.HtmlEditorCore.remove = [
16306 Roo.HtmlEditorCore.ablack = [
16310 Roo.HtmlEditorCore.aclean = [
16311 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
16315 Roo.HtmlEditorCore.pwhite= [
16316 'http', 'https', 'mailto'
16319 // white listed style attributes.
16320 Roo.HtmlEditorCore.cwhite= [
16321 // 'text-align', /// default is to allow most things..
16327 // black listed style attributes.
16328 Roo.HtmlEditorCore.cblack= [
16329 // 'font-size' -- this can be set by the project
16333 Roo.HtmlEditorCore.swapCodes =[
16352 * @class Roo.bootstrap.HtmlEditor
16353 * @extends Roo.bootstrap.TextArea
16354 * Bootstrap HtmlEditor class
16357 * Create a new HtmlEditor
16358 * @param {Object} config The config object
16361 Roo.bootstrap.HtmlEditor = function(config){
16362 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
16363 if (!this.toolbars) {
16364 this.toolbars = [];
16366 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
16369 * @event initialize
16370 * Fires when the editor is fully initialized (including the iframe)
16371 * @param {HtmlEditor} this
16376 * Fires when the editor is first receives the focus. Any insertion must wait
16377 * until after this event.
16378 * @param {HtmlEditor} this
16382 * @event beforesync
16383 * Fires before the textarea is updated with content from the editor iframe. Return false
16384 * to cancel the sync.
16385 * @param {HtmlEditor} this
16386 * @param {String} html
16390 * @event beforepush
16391 * Fires before the iframe editor is updated with content from the textarea. Return false
16392 * to cancel the push.
16393 * @param {HtmlEditor} this
16394 * @param {String} html
16399 * Fires when the textarea is updated with content from the editor iframe.
16400 * @param {HtmlEditor} this
16401 * @param {String} html
16406 * Fires when the iframe editor is updated with content from the textarea.
16407 * @param {HtmlEditor} this
16408 * @param {String} html
16412 * @event editmodechange
16413 * Fires when the editor switches edit modes
16414 * @param {HtmlEditor} this
16415 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
16417 editmodechange: true,
16419 * @event editorevent
16420 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16421 * @param {HtmlEditor} this
16425 * @event firstfocus
16426 * Fires when on first focus - needed by toolbars..
16427 * @param {HtmlEditor} this
16432 * Auto save the htmlEditor value as a file into Events
16433 * @param {HtmlEditor} this
16437 * @event savedpreview
16438 * preview the saved version of htmlEditor
16439 * @param {HtmlEditor} this
16446 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
16450 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
16455 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16460 * @cfg {Number} height (in pixels)
16464 * @cfg {Number} width (in pixels)
16469 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16472 stylesheets: false,
16477 // private properties
16478 validationEvent : false,
16480 initialized : false,
16483 onFocus : Roo.emptyFn,
16485 hideMode:'offsets',
16488 tbContainer : false,
16490 toolbarContainer :function() {
16491 return this.wrap.select('.x-html-editor-tb',true).first();
16495 * Protected method that will not generally be called directly. It
16496 * is called when the editor creates its toolbar. Override this method if you need to
16497 * add custom toolbar buttons.
16498 * @param {HtmlEditor} editor
16500 createToolbar : function(){
16502 Roo.log("create toolbars");
16504 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
16505 this.toolbars[0].render(this.toolbarContainer());
16509 // if (!editor.toolbars || !editor.toolbars.length) {
16510 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
16513 // for (var i =0 ; i < editor.toolbars.length;i++) {
16514 // editor.toolbars[i] = Roo.factory(
16515 // typeof(editor.toolbars[i]) == 'string' ?
16516 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
16517 // Roo.bootstrap.HtmlEditor);
16518 // editor.toolbars[i].init(editor);
16524 onRender : function(ct, position)
16526 // Roo.log("Call onRender: " + this.xtype);
16528 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
16530 this.wrap = this.inputEl().wrap({
16531 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
16534 this.editorcore.onRender(ct, position);
16536 if (this.resizable) {
16537 this.resizeEl = new Roo.Resizable(this.wrap, {
16541 minHeight : this.height,
16542 height: this.height,
16543 handles : this.resizable,
16546 resize : function(r, w, h) {
16547 _t.onResize(w,h); // -something
16553 this.createToolbar(this);
16556 if(!this.width && this.resizable){
16557 this.setSize(this.wrap.getSize());
16559 if (this.resizeEl) {
16560 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
16561 // should trigger onReize..
16567 onResize : function(w, h)
16569 Roo.log('resize: ' +w + ',' + h );
16570 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
16574 if(this.inputEl() ){
16575 if(typeof w == 'number'){
16576 var aw = w - this.wrap.getFrameWidth('lr');
16577 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
16580 if(typeof h == 'number'){
16581 var tbh = -11; // fixme it needs to tool bar size!
16582 for (var i =0; i < this.toolbars.length;i++) {
16583 // fixme - ask toolbars for heights?
16584 tbh += this.toolbars[i].el.getHeight();
16585 //if (this.toolbars[i].footer) {
16586 // tbh += this.toolbars[i].footer.el.getHeight();
16594 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
16595 ah -= 5; // knock a few pixes off for look..
16596 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
16600 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
16601 this.editorcore.onResize(ew,eh);
16606 * Toggles the editor between standard and source edit mode.
16607 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16609 toggleSourceEdit : function(sourceEditMode)
16611 this.editorcore.toggleSourceEdit(sourceEditMode);
16613 if(this.editorcore.sourceEditMode){
16614 Roo.log('editor - showing textarea');
16617 // Roo.log(this.syncValue());
16619 this.inputEl().removeClass('hide');
16620 this.inputEl().dom.removeAttribute('tabIndex');
16621 this.inputEl().focus();
16623 Roo.log('editor - hiding textarea');
16625 // Roo.log(this.pushValue());
16628 this.inputEl().addClass('hide');
16629 this.inputEl().dom.setAttribute('tabIndex', -1);
16630 //this.deferFocus();
16633 if(this.resizable){
16634 this.setSize(this.wrap.getSize());
16637 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
16640 // private (for BoxComponent)
16641 adjustSize : Roo.BoxComponent.prototype.adjustSize,
16643 // private (for BoxComponent)
16644 getResizeEl : function(){
16648 // private (for BoxComponent)
16649 getPositionEl : function(){
16654 initEvents : function(){
16655 this.originalValue = this.getValue();
16659 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16662 // markInvalid : Roo.emptyFn,
16664 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16667 // clearInvalid : Roo.emptyFn,
16669 setValue : function(v){
16670 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
16671 this.editorcore.pushValue();
16676 deferFocus : function(){
16677 this.focus.defer(10, this);
16681 focus : function(){
16682 this.editorcore.focus();
16688 onDestroy : function(){
16694 for (var i =0; i < this.toolbars.length;i++) {
16695 // fixme - ask toolbars for heights?
16696 this.toolbars[i].onDestroy();
16699 this.wrap.dom.innerHTML = '';
16700 this.wrap.remove();
16705 onFirstFocus : function(){
16706 //Roo.log("onFirstFocus");
16707 this.editorcore.onFirstFocus();
16708 for (var i =0; i < this.toolbars.length;i++) {
16709 this.toolbars[i].onFirstFocus();
16715 syncValue : function()
16717 this.editorcore.syncValue();
16720 pushValue : function()
16722 this.editorcore.pushValue();
16726 // hide stuff that is not compatible
16740 * @event specialkey
16744 * @cfg {String} fieldClass @hide
16747 * @cfg {String} focusClass @hide
16750 * @cfg {String} autoCreate @hide
16753 * @cfg {String} inputType @hide
16756 * @cfg {String} invalidClass @hide
16759 * @cfg {String} invalidText @hide
16762 * @cfg {String} msgFx @hide
16765 * @cfg {String} validateOnBlur @hide
16774 Roo.namespace('Roo.bootstrap.htmleditor');
16776 * @class Roo.bootstrap.HtmlEditorToolbar1
16781 new Roo.bootstrap.HtmlEditor({
16784 new Roo.bootstrap.HtmlEditorToolbar1({
16785 disable : { fonts: 1 , format: 1, ..., ... , ...],
16791 * @cfg {Object} disable List of elements to disable..
16792 * @cfg {Array} btns List of additional buttons.
16796 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16799 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
16802 Roo.apply(this, config);
16804 // default disabled, based on 'good practice'..
16805 this.disable = this.disable || {};
16806 Roo.applyIf(this.disable, {
16809 specialElements : true
16811 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
16813 this.editor = config.editor;
16814 this.editorcore = config.editor.editorcore;
16816 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16818 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16819 // dont call parent... till later.
16821 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16826 editorcore : false,
16831 "h1","h2","h3","h4","h5","h6",
16833 "abbr", "acronym", "address", "cite", "samp", "var",
16837 onRender : function(ct, position)
16839 // Roo.log("Call onRender: " + this.xtype);
16841 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16843 this.el.dom.style.marginBottom = '0';
16845 var editorcore = this.editorcore;
16846 var editor= this.editor;
16849 var btn = function(id,cmd , toggle, handler){
16851 var event = toggle ? 'toggle' : 'click';
16856 xns: Roo.bootstrap,
16859 enableToggle:toggle !== false,
16861 pressed : toggle ? false : null,
16864 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16865 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16874 xns: Roo.bootstrap,
16875 glyphicon : 'font',
16879 xns: Roo.bootstrap,
16883 Roo.each(this.formats, function(f) {
16884 style.menu.items.push({
16886 xns: Roo.bootstrap,
16887 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
16892 editorcore.insertTag(this.tagname);
16899 children.push(style);
16902 btn('bold',false,true);
16903 btn('italic',false,true);
16904 btn('align-left', 'justifyleft',true);
16905 btn('align-center', 'justifycenter',true);
16906 btn('align-right' , 'justifyright',true);
16907 btn('link', false, false, function(btn) {
16908 //Roo.log("create link?");
16909 var url = prompt(this.createLinkText, this.defaultLinkValue);
16910 if(url && url != 'http:/'+'/'){
16911 this.editorcore.relayCmd('createlink', url);
16914 btn('list','insertunorderedlist',true);
16915 btn('pencil', false,true, function(btn){
16918 this.toggleSourceEdit(btn.pressed);
16924 xns: Roo.bootstrap,
16929 xns: Roo.bootstrap,
16934 cog.menu.items.push({
16936 xns: Roo.bootstrap,
16937 html : Clean styles,
16942 editorcore.insertTag(this.tagname);
16951 this.xtype = 'NavSimplebar';
16953 for(var i=0;i< children.length;i++) {
16955 this.buttons.add(this.addxtypeChild(children[i]));
16959 editor.on('editorevent', this.updateToolbar, this);
16961 onBtnClick : function(id)
16963 this.editorcore.relayCmd(id);
16964 this.editorcore.focus();
16968 * Protected method that will not generally be called directly. It triggers
16969 * a toolbar update by reading the markup state of the current selection in the editor.
16971 updateToolbar: function(){
16973 if(!this.editorcore.activated){
16974 this.editor.onFirstFocus(); // is this neeed?
16978 var btns = this.buttons;
16979 var doc = this.editorcore.doc;
16980 btns.get('bold').setActive(doc.queryCommandState('bold'));
16981 btns.get('italic').setActive(doc.queryCommandState('italic'));
16982 //btns.get('underline').setActive(doc.queryCommandState('underline'));
16984 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
16985 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
16986 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
16988 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
16989 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
16992 var ans = this.editorcore.getAllAncestors();
16993 if (this.formatCombo) {
16996 var store = this.formatCombo.store;
16997 this.formatCombo.setValue("");
16998 for (var i =0; i < ans.length;i++) {
16999 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17001 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17009 // hides menus... - so this cant be on a menu...
17010 Roo.bootstrap.MenuMgr.hideAll();
17012 Roo.bootstrap.MenuMgr.hideAll();
17013 //this.editorsyncValue();
17015 onFirstFocus: function() {
17016 this.buttons.each(function(item){
17020 toggleSourceEdit : function(sourceEditMode){
17023 if(sourceEditMode){
17024 Roo.log("disabling buttons");
17025 this.buttons.each( function(item){
17026 if(item.cmd != 'pencil'){
17032 Roo.log("enabling buttons");
17033 if(this.editorcore.initialized){
17034 this.buttons.each( function(item){
17040 Roo.log("calling toggole on editor");
17041 // tell the editor that it's been pressed..
17042 this.editor.toggleSourceEdit(sourceEditMode);
17052 * @class Roo.bootstrap.Table.AbstractSelectionModel
17053 * @extends Roo.util.Observable
17054 * Abstract base class for grid SelectionModels. It provides the interface that should be
17055 * implemented by descendant classes. This class should not be directly instantiated.
17058 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17059 this.locked = false;
17060 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17064 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
17065 /** @ignore Called by the grid automatically. Do not call directly. */
17066 init : function(grid){
17072 * Locks the selections.
17075 this.locked = true;
17079 * Unlocks the selections.
17081 unlock : function(){
17082 this.locked = false;
17086 * Returns true if the selections are locked.
17087 * @return {Boolean}
17089 isLocked : function(){
17090 return this.locked;
17094 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17095 * @class Roo.bootstrap.Table.RowSelectionModel
17096 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17097 * It supports multiple selections and keyboard selection/navigation.
17099 * @param {Object} config
17102 Roo.bootstrap.Table.RowSelectionModel = function(config){
17103 Roo.apply(this, config);
17104 this.selections = new Roo.util.MixedCollection(false, function(o){
17109 this.lastActive = false;
17113 * @event selectionchange
17114 * Fires when the selection changes
17115 * @param {SelectionModel} this
17117 "selectionchange" : true,
17119 * @event afterselectionchange
17120 * Fires after the selection changes (eg. by key press or clicking)
17121 * @param {SelectionModel} this
17123 "afterselectionchange" : true,
17125 * @event beforerowselect
17126 * Fires when a row is selected being selected, return false to cancel.
17127 * @param {SelectionModel} this
17128 * @param {Number} rowIndex The selected index
17129 * @param {Boolean} keepExisting False if other selections will be cleared
17131 "beforerowselect" : true,
17134 * Fires when a row is selected.
17135 * @param {SelectionModel} this
17136 * @param {Number} rowIndex The selected index
17137 * @param {Roo.data.Record} r The record
17139 "rowselect" : true,
17141 * @event rowdeselect
17142 * Fires when a row is deselected.
17143 * @param {SelectionModel} this
17144 * @param {Number} rowIndex The selected index
17146 "rowdeselect" : true
17148 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17149 this.locked = false;
17152 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17154 * @cfg {Boolean} singleSelect
17155 * True to allow selection of only one row at a time (defaults to false)
17157 singleSelect : false,
17160 initEvents : function(){
17162 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17163 this.grid.on("mousedown", this.handleMouseDown, this);
17164 }else{ // allow click to work like normal
17165 this.grid.on("rowclick", this.handleDragableRowClick, this);
17168 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17169 "up" : function(e){
17171 this.selectPrevious(e.shiftKey);
17172 }else if(this.last !== false && this.lastActive !== false){
17173 var last = this.last;
17174 this.selectRange(this.last, this.lastActive-1);
17175 this.grid.getView().focusRow(this.lastActive);
17176 if(last !== false){
17180 this.selectFirstRow();
17182 this.fireEvent("afterselectionchange", this);
17184 "down" : function(e){
17186 this.selectNext(e.shiftKey);
17187 }else if(this.last !== false && this.lastActive !== false){
17188 var last = this.last;
17189 this.selectRange(this.last, this.lastActive+1);
17190 this.grid.getView().focusRow(this.lastActive);
17191 if(last !== false){
17195 this.selectFirstRow();
17197 this.fireEvent("afterselectionchange", this);
17202 var view = this.grid.view;
17203 view.on("refresh", this.onRefresh, this);
17204 view.on("rowupdated", this.onRowUpdated, this);
17205 view.on("rowremoved", this.onRemove, this);
17209 onRefresh : function(){
17210 var ds = this.grid.dataSource, i, v = this.grid.view;
17211 var s = this.selections;
17212 s.each(function(r){
17213 if((i = ds.indexOfId(r.id)) != -1){
17222 onRemove : function(v, index, r){
17223 this.selections.remove(r);
17227 onRowUpdated : function(v, index, r){
17228 if(this.isSelected(r)){
17229 v.onRowSelect(index);
17235 * @param {Array} records The records to select
17236 * @param {Boolean} keepExisting (optional) True to keep existing selections
17238 selectRecords : function(records, keepExisting){
17240 this.clearSelections();
17242 var ds = this.grid.dataSource;
17243 for(var i = 0, len = records.length; i < len; i++){
17244 this.selectRow(ds.indexOf(records[i]), true);
17249 * Gets the number of selected rows.
17252 getCount : function(){
17253 return this.selections.length;
17257 * Selects the first row in the grid.
17259 selectFirstRow : function(){
17264 * Select the last row.
17265 * @param {Boolean} keepExisting (optional) True to keep existing selections
17267 selectLastRow : function(keepExisting){
17268 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17272 * Selects the row immediately following the last selected row.
17273 * @param {Boolean} keepExisting (optional) True to keep existing selections
17275 selectNext : function(keepExisting){
17276 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17277 this.selectRow(this.last+1, keepExisting);
17278 this.grid.getView().focusRow(this.last);
17283 * Selects the row that precedes the last selected row.
17284 * @param {Boolean} keepExisting (optional) True to keep existing selections
17286 selectPrevious : function(keepExisting){
17288 this.selectRow(this.last-1, keepExisting);
17289 this.grid.getView().focusRow(this.last);
17294 * Returns the selected records
17295 * @return {Array} Array of selected records
17297 getSelections : function(){
17298 return [].concat(this.selections.items);
17302 * Returns the first selected record.
17305 getSelected : function(){
17306 return this.selections.itemAt(0);
17311 * Clears all selections.
17313 clearSelections : function(fast){
17314 if(this.locked) return;
17316 var ds = this.grid.dataSource;
17317 var s = this.selections;
17318 s.each(function(r){
17319 this.deselectRow(ds.indexOfId(r.id));
17323 this.selections.clear();
17330 * Selects all rows.
17332 selectAll : function(){
17333 if(this.locked) return;
17334 this.selections.clear();
17335 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17336 this.selectRow(i, true);
17341 * Returns True if there is a selection.
17342 * @return {Boolean}
17344 hasSelection : function(){
17345 return this.selections.length > 0;
17349 * Returns True if the specified row is selected.
17350 * @param {Number/Record} record The record or index of the record to check
17351 * @return {Boolean}
17353 isSelected : function(index){
17354 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17355 return (r && this.selections.key(r.id) ? true : false);
17359 * Returns True if the specified record id is selected.
17360 * @param {String} id The id of record to check
17361 * @return {Boolean}
17363 isIdSelected : function(id){
17364 return (this.selections.key(id) ? true : false);
17368 handleMouseDown : function(e, t){
17369 var view = this.grid.getView(), rowIndex;
17370 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17373 if(e.shiftKey && this.last !== false){
17374 var last = this.last;
17375 this.selectRange(last, rowIndex, e.ctrlKey);
17376 this.last = last; // reset the last
17377 view.focusRow(rowIndex);
17379 var isSelected = this.isSelected(rowIndex);
17380 if(e.button !== 0 && isSelected){
17381 view.focusRow(rowIndex);
17382 }else if(e.ctrlKey && isSelected){
17383 this.deselectRow(rowIndex);
17384 }else if(!isSelected){
17385 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17386 view.focusRow(rowIndex);
17389 this.fireEvent("afterselectionchange", this);
17392 handleDragableRowClick : function(grid, rowIndex, e)
17394 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17395 this.selectRow(rowIndex, false);
17396 grid.view.focusRow(rowIndex);
17397 this.fireEvent("afterselectionchange", this);
17402 * Selects multiple rows.
17403 * @param {Array} rows Array of the indexes of the row to select
17404 * @param {Boolean} keepExisting (optional) True to keep existing selections
17406 selectRows : function(rows, keepExisting){
17408 this.clearSelections();
17410 for(var i = 0, len = rows.length; i < len; i++){
17411 this.selectRow(rows[i], true);
17416 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17417 * @param {Number} startRow The index of the first row in the range
17418 * @param {Number} endRow The index of the last row in the range
17419 * @param {Boolean} keepExisting (optional) True to retain existing selections
17421 selectRange : function(startRow, endRow, keepExisting){
17422 if(this.locked) return;
17424 this.clearSelections();
17426 if(startRow <= endRow){
17427 for(var i = startRow; i <= endRow; i++){
17428 this.selectRow(i, true);
17431 for(var i = startRow; i >= endRow; i--){
17432 this.selectRow(i, true);
17438 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17439 * @param {Number} startRow The index of the first row in the range
17440 * @param {Number} endRow The index of the last row in the range
17442 deselectRange : function(startRow, endRow, preventViewNotify){
17443 if(this.locked) return;
17444 for(var i = startRow; i <= endRow; i++){
17445 this.deselectRow(i, preventViewNotify);
17451 * @param {Number} row The index of the row to select
17452 * @param {Boolean} keepExisting (optional) True to keep existing selections
17454 selectRow : function(index, keepExisting, preventViewNotify){
17455 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17456 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17457 if(!keepExisting || this.singleSelect){
17458 this.clearSelections();
17460 var r = this.grid.dataSource.getAt(index);
17461 this.selections.add(r);
17462 this.last = this.lastActive = index;
17463 if(!preventViewNotify){
17464 this.grid.getView().onRowSelect(index);
17466 this.fireEvent("rowselect", this, index, r);
17467 this.fireEvent("selectionchange", this);
17473 * @param {Number} row The index of the row to deselect
17475 deselectRow : function(index, preventViewNotify){
17476 if(this.locked) return;
17477 if(this.last == index){
17480 if(this.lastActive == index){
17481 this.lastActive = false;
17483 var r = this.grid.dataSource.getAt(index);
17484 this.selections.remove(r);
17485 if(!preventViewNotify){
17486 this.grid.getView().onRowDeselect(index);
17488 this.fireEvent("rowdeselect", this, index);
17489 this.fireEvent("selectionchange", this);
17493 restoreLast : function(){
17495 this.last = this._last;
17500 acceptsNav : function(row, col, cm){
17501 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17505 onEditorKey : function(field, e){
17506 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17511 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17513 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17515 }else if(k == e.ENTER && !e.ctrlKey){
17519 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17521 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17523 }else if(k == e.ESC){
17527 g.startEditing(newCell[0], newCell[1]);
17532 * Ext JS Library 1.1.1
17533 * Copyright(c) 2006-2007, Ext JS, LLC.
17535 * Originally Released Under LGPL - original licence link has changed is not relivant.
17538 * <script type="text/javascript">
17542 * @class Roo.bootstrap.PagingToolbar
17544 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
17546 * Create a new PagingToolbar
17547 * @param {Object} config The config object
17549 Roo.bootstrap.PagingToolbar = function(config)
17551 // old args format still supported... - xtype is prefered..
17552 // created from xtype...
17553 var ds = config.dataSource;
17555 if (config.items) {
17556 items = config.items;
17560 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
17567 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
17569 // supprot items array.
17571 Roo.each(items, function(e) {
17572 this.add(Roo.factory(e));
17581 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
17583 * @cfg {Roo.data.Store} dataSource
17584 * The underlying data store providing the paged data
17587 * @cfg {String/HTMLElement/Element} container
17588 * container The id or element that will contain the toolbar
17591 * @cfg {Boolean} displayInfo
17592 * True to display the displayMsg (defaults to false)
17595 * @cfg {Number} pageSize
17596 * The number of records to display per page (defaults to 20)
17600 * @cfg {String} displayMsg
17601 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
17603 displayMsg : 'Displaying {0} - {1} of {2}',
17605 * @cfg {String} emptyMsg
17606 * The message to display when no records are found (defaults to "No data to display")
17608 emptyMsg : 'No data to display',
17610 * Customizable piece of the default paging text (defaults to "Page")
17613 beforePageText : "Page",
17615 * Customizable piece of the default paging text (defaults to "of %0")
17618 afterPageText : "of {0}",
17620 * Customizable piece of the default paging text (defaults to "First Page")
17623 firstText : "First Page",
17625 * Customizable piece of the default paging text (defaults to "Previous Page")
17628 prevText : "Previous Page",
17630 * Customizable piece of the default paging text (defaults to "Next Page")
17633 nextText : "Next Page",
17635 * Customizable piece of the default paging text (defaults to "Last Page")
17638 lastText : "Last Page",
17640 * Customizable piece of the default paging text (defaults to "Refresh")
17643 refreshText : "Refresh",
17646 onRender : function(ct, position)
17648 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
17649 this.navgroup.parentId = this.id;
17650 this.navgroup.onRender(this.el, null);
17651 // add the buttons to the navgroup
17653 this.first = this.navgroup.addItem({
17654 tooltip: this.firstText,
17656 icon : 'fa fa-backward',
17658 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
17661 this.prev = this.navgroup.addItem({
17662 tooltip: this.prevText,
17664 icon : 'fa fa-step-backward',
17666 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
17668 //this.addSeparator();
17671 var field = this.navgroup.addItem( {
17673 cls : 'x-paging-position',
17675 html : this.beforePageText +
17676 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
17677 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
17680 this.field = field.el.select('input', true).first();
17681 this.field.on("keydown", this.onPagingKeydown, this);
17682 this.field.on("focus", function(){this.dom.select();});
17685 this.afterTextEl = field.el.select('.x-paging-after',true).first();
17686 //this.field.setHeight(18);
17687 //this.addSeparator();
17688 this.next = this.navgroup.addItem({
17689 tooltip: this.nextText,
17691 html : ' <i class="fa fa-step-forward">',
17693 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
17695 this.last = this.navgroup.addItem({
17696 tooltip: this.lastText,
17697 icon : 'fa fa-forward',
17700 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
17702 //this.addSeparator();
17703 this.loading = this.navgroup.addItem({
17704 tooltip: this.refreshText,
17705 icon: 'fa fa-refresh',
17707 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
17710 if(this.displayInfo){
17711 var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info' } );
17712 this.displayEl = navel.el.select('a',true).first();
17718 updateInfo : function(){
17719 if(this.displayEl){
17720 var count = this.ds.getCount();
17721 var msg = count == 0 ?
17725 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
17727 this.displayEl.update(msg);
17732 onLoad : function(ds, r, o){
17733 this.cursor = o.params ? o.params.start : 0;
17734 var d = this.getPageData(),
17738 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
17739 this.field.dom.value = ap;
17740 this.first.setDisabled(ap == 1);
17741 this.prev.setDisabled(ap == 1);
17742 this.next.setDisabled(ap == ps);
17743 this.last.setDisabled(ap == ps);
17744 this.loading.enable();
17749 getPageData : function(){
17750 var total = this.ds.getTotalCount();
17753 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
17754 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
17759 onLoadError : function(){
17760 this.loading.enable();
17764 onPagingKeydown : function(e){
17765 var k = e.getKey();
17766 var d = this.getPageData();
17768 var v = this.field.dom.value, pageNum;
17769 if(!v || isNaN(pageNum = parseInt(v, 10))){
17770 this.field.dom.value = d.activePage;
17773 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
17774 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
17777 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))
17779 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
17780 this.field.dom.value = pageNum;
17781 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
17784 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
17786 var v = this.field.dom.value, pageNum;
17787 var increment = (e.shiftKey) ? 10 : 1;
17788 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
17790 if(!v || isNaN(pageNum = parseInt(v, 10))) {
17791 this.field.dom.value = d.activePage;
17794 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
17796 this.field.dom.value = parseInt(v, 10) + increment;
17797 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
17798 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
17805 beforeLoad : function(){
17807 this.loading.disable();
17812 onClick : function(which){
17819 ds.load({params:{start: 0, limit: this.pageSize}});
17822 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
17825 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
17828 var total = ds.getTotalCount();
17829 var extra = total % this.pageSize;
17830 var lastStart = extra ? (total - extra) : total-this.pageSize;
17831 ds.load({params:{start: lastStart, limit: this.pageSize}});
17834 ds.load({params:{start: this.cursor, limit: this.pageSize}});
17840 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
17841 * @param {Roo.data.Store} store The data store to unbind
17843 unbind : function(ds){
17844 ds.un("beforeload", this.beforeLoad, this);
17845 ds.un("load", this.onLoad, this);
17846 ds.un("loadexception", this.onLoadError, this);
17847 ds.un("remove", this.updateInfo, this);
17848 ds.un("add", this.updateInfo, this);
17849 this.ds = undefined;
17853 * Binds the paging toolbar to the specified {@link Roo.data.Store}
17854 * @param {Roo.data.Store} store The data store to bind
17856 bind : function(ds){
17857 ds.on("beforeload", this.beforeLoad, this);
17858 ds.on("load", this.onLoad, this);
17859 ds.on("loadexception", this.onLoadError, this);
17860 ds.on("remove", this.updateInfo, this);
17861 ds.on("add", this.updateInfo, this);
17872 * @class Roo.bootstrap.MessageBar
17873 * @extends Roo.bootstrap.Component
17874 * Bootstrap MessageBar class
17875 * @cfg {String} html contents of the MessageBar
17876 * @cfg {String} weight (info | success | warning | danger) default info
17877 * @cfg {String} beforeClass insert the bar before the given class
17878 * @cfg {Boolean} closable (true | false) default false
17879 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
17882 * Create a new Element
17883 * @param {Object} config The config object
17886 Roo.bootstrap.MessageBar = function(config){
17887 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
17890 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
17896 beforeClass: 'bootstrap-sticky-wrap',
17898 getAutoCreate : function(){
17902 cls: 'alert alert-dismissable alert-' + this.weight,
17907 html: this.html || ''
17913 cfg.cls += ' alert-messages-fixed';
17927 onRender : function(ct, position)
17929 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17932 var cfg = Roo.apply({}, this.getAutoCreate());
17936 cfg.cls += ' ' + this.cls;
17939 cfg.style = this.style;
17941 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
17943 this.el.setVisibilityMode(Roo.Element.DISPLAY);
17946 this.el.select('>button.close').on('click', this.hide, this);
17952 if (!this.rendered) {
17958 this.fireEvent('show', this);
17964 if (!this.rendered) {
17970 this.fireEvent('hide', this);
17973 update : function()
17975 // var e = this.el.dom.firstChild;
17977 // if(this.closable){
17978 // e = e.nextSibling;
17981 // e.data = this.html || '';
17983 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';