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]());
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)
183 cntr = typeof(cntr == 'undefined' ) ? 'getChildContainer' : cntr;
186 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
187 (typeof(tree['flexy:foreach']) != 'undefined');
192 // render the element if it's not BODY.
193 if (tree.xtype != 'Body') {
195 cn = Roo.factory(tree);
197 cn.parentType = this.xtype; //??
198 cn.parentId = this.id;
200 var build_from_html = Roo.XComponent.build_from_html;
203 // does the container contain child eleemnts with 'xtype' attributes.
204 // that match this xtype..
205 // note - when we render we create these as well..
206 // so we should check to see if body has xtype set.
207 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
209 var self_cntr_el = Roo.get(this[cntr]());
210 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
212 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
213 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
219 //echild.dom.removeAttribute('xtype');
221 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
228 // if object has flexy:if - then it may or may not be rendered.
229 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
230 // skip a flexy if element.
231 Roo.log('skipping render');
234 // actually if flexy:foreach is found, we really want to create
235 // multiple copies here...
237 cn.render(this[cntr]());
239 // then add the element..
246 if (typeof (tree.menu) != 'undefined') {
247 tree.menu.parentType = cn.xtype;
248 tree.menu.triggerEl = cn.el;
249 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
253 if (!tree.items || !tree.items.length) {
257 var items = tree.items;
260 //Roo.log(items.length);
262 for(var i =0;i < items.length;i++) {
263 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
282 Roo.bootstrap.Body = function(config){
283 Roo.bootstrap.Body.superclass.constructor.call(this, config);
284 this.el = Roo.get(document.body);
287 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
292 onRender : function(ct, position){
295 //this.el.addClass([this.fieldClass, this.cls]);
313 * @class Roo.bootstrap.ButtonGroup
314 * @extends Roo.bootstrap.Component
315 * Bootstrap ButtonGroup class
316 * @cfg {String} size lg | sm | xs (default empty normal)
317 * @cfg {String} align vertical | justified (default none)
318 * @cfg {String} direction up | down (default down)
319 * @cfg {Boolean} toolbar false | true
320 * @cfg {Boolean} btn true | false
325 * @param {Object} config The config object
328 Roo.bootstrap.ButtonGroup = function(config){
329 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
332 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
340 getAutoCreate : function(){
346 cfg.html = this.html || cfg.html;
357 if (['vertical','justified'].indexOf(this.align)!==-1) {
358 cfg.cls = 'btn-group-' + this.align;
360 if (this.align == 'justified') {
361 console.log(this.items);
365 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
366 cfg.cls += ' btn-group-' + this.size;
369 if (this.direction == 'up') {
370 cfg.cls += ' dropup' ;
386 * @class Roo.bootstrap.Button
387 * @extends Roo.bootstrap.Component
388 * Bootstrap Button class
389 * @cfg {String} html The button content
390 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
391 * @cfg {String} size empty | lg | sm | xs
392 * @cfg {String} tag empty | a | input | submit
393 * @cfg {String} href empty or href
394 * @cfg {Boolean} disabled false | true
395 * @cfg {Boolean} isClose false | true
396 * @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
397 * @cfg {String} badge text for badge
398 * @cfg {String} theme default (or empty) | glow
399 * @cfg {Boolean} inverse false | true
400 * @cfg {Boolean} toggle false | true
401 * @cfg {String} ontext text for on toggle state
402 * @cfg {String} offtext text for off toggle state
403 * @cfg {Boolean} defaulton true | false
404 * @cfg {Boolean} preventDefault (true | false) default true
405 * @cfg {Boolean} removeClass true | false remove the standard class..
406 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
409 * Create a new button
410 * @param {Object} config The config object
414 Roo.bootstrap.Button = function(config){
415 Roo.bootstrap.Button.superclass.constructor.call(this, config);
420 * The raw click event for the entire grid.
421 * @param {Roo.EventObject} e
427 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
445 preventDefault: true,
450 getAutoCreate : function(){
458 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
459 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
464 cfg.html = this.html || cfg.html;
466 if (this.toggle===true) {
469 cls: 'slider-frame roo-button',
474 'data-off-text':'OFF',
475 cls: 'slider-button',
481 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
482 cfg.cls += ' '+this.weight;
491 cfg["aria-hidden"] = true;
493 cfg.html = "×";
499 if (this.theme==='default') {
500 cfg.cls = 'btn roo-button';
502 if (this.parentType != 'Navbar') {
503 this.weight = this.weight.length ? this.weight : 'default';
505 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
507 cfg.cls += ' btn-' + this.weight;
509 } else if (this.theme==='glow') {
512 cfg.cls = 'btn-glow roo-button';
514 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
516 cfg.cls += ' ' + this.weight;
522 this.cls += ' inverse';
527 cfg.cls += ' active';
531 cfg.disabled = 'disabled';
535 Roo.log('changing to ul' );
537 this.glyphicon = 'caret';
540 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
542 //gsRoo.log(this.parentType);
543 if (this.parentType === 'Navbar') {
551 href : this.href || '#'
554 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
555 cfg.cls += ' dropdown';
562 if (this.glyphicon) {
563 cfg.html = ' ' + cfg.html;
568 cls: 'glyphicon glyphicon-' + this.glyphicon
578 // cfg.cls='btn roo-button';
582 var value = cfg.html;
587 cls: 'glyphicon glyphicon-' + this.glyphicon,
606 cfg.cls += ' dropdown';
607 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
610 if (cfg.tag !== 'a' && this.href !== '') {
611 throw "Tag must be a to set href.";
612 } else if (this.href.length > 0) {
613 cfg.href = this.href;
616 if(this.removeClass){
621 cfg.target = this.target;
626 initEvents: function() {
627 // Roo.log('init events?');
628 // Roo.log(this.el.dom);
629 if (this.el.hasClass('roo-button')) {
630 this.el.on('click', this.onClick, this);
632 this.el.select('.roo-button').on('click', this.onClick, this);
638 onClick : function(e)
640 Roo.log('button on click ');
641 if(this.preventDefault){
645 this.fireEvent('click', this, e);
659 * @class Roo.bootstrap.Column
660 * @extends Roo.bootstrap.Component
661 * Bootstrap Column class
662 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
663 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
664 * @cfg {Number} md colspan out of 12 for computer-sized screens
665 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
666 * @cfg {String} html content of column.
669 * Create a new Column
670 * @param {Object} config The config object
673 Roo.bootstrap.Column = function(config){
674 Roo.bootstrap.Column.superclass.constructor.call(this, config);
677 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
686 getAutoCreate : function(){
687 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
695 ['xs','sm','md','lg'].map(function(size){
696 if (settings[size]) {
697 cfg.cls += ' col-' + size + '-' + settings[size];
700 if (this.html.length) {
701 cfg.html = this.html;
720 * @class Roo.bootstrap.Container
721 * @extends Roo.bootstrap.Component
722 * Bootstrap Container class
723 * @cfg {Boolean} jumbotron is it a jumbotron element
724 * @cfg {String} html content of element
725 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
726 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
727 * @cfg {String} header content of header (for panel)
728 * @cfg {String} footer content of footer (for panel)
729 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
732 * Create a new Container
733 * @param {Object} config The config object
736 Roo.bootstrap.Container = function(config){
737 Roo.bootstrap.Container.superclass.constructor.call(this, config);
740 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
750 getChildContainer : function() {
756 if (this.panel.length) {
757 return this.el.select('.panel-body',true).first();
764 getAutoCreate : function(){
770 if (this.jumbotron) {
771 cfg.cls = 'jumbotron';
774 cfg.cls = this.cls + '';
777 if (this.sticky.length) {
779 var bd = Roo.get(document.body);
780 if (!bd.hasClass('bootstrap-sticky')) {
781 bd.addClass('bootstrap-sticky');
782 Roo.select('html',true).setStyle('height', '100%');
785 cfg.cls += 'bootstrap-sticky-' + this.sticky;
789 if (this.well.length) {
793 cfg.cls +=' well well-' +this.well;
803 if (this.panel.length) {
804 cfg.cls += ' panel panel-' + this.panel;
806 if (this.header.length) {
809 cls : 'panel-heading',
825 if (this.footer.length) {
827 cls : 'panel-footer',
835 body.html = this.html || cfg.html;
837 if (!cfg.cls.length) {
838 cfg.cls = 'container';
855 * @class Roo.bootstrap.Img
856 * @extends Roo.bootstrap.Component
857 * Bootstrap Img class
858 * @cfg {Boolean} imgResponsive false | true
859 * @cfg {String} border rounded | circle | thumbnail
860 * @cfg {String} src image source
861 * @cfg {String} alt image alternative text
862 * @cfg {String} href a tag href
863 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
867 * @param {Object} config The config object
870 Roo.bootstrap.Img = function(config){
871 Roo.bootstrap.Img.superclass.constructor.call(this, config);
877 * The img click event for the img.
878 * @param {Roo.EventObject} e
884 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
892 getAutoCreate : function(){
896 cls: 'img-responsive',
900 cfg.html = this.html || cfg.html;
902 cfg.src = this.src || cfg.src;
904 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
905 cfg.cls += ' img-' + this.border;
922 a.target = this.target;
928 return (this.href) ? a : cfg;
931 initEvents: function() {
934 this.el.on('click', this.onClick, this);
938 onClick : function(e)
940 Roo.log('img onclick');
941 this.fireEvent('click', this, e);
954 * @class Roo.bootstrap.Header
955 * @extends Roo.bootstrap.Component
956 * Bootstrap Header class
957 * @cfg {String} html content of header
958 * @cfg {Number} level (1|2|3|4|5|6) default 1
961 * Create a new Header
962 * @param {Object} config The config object
966 Roo.bootstrap.Header = function(config){
967 Roo.bootstrap.Header.superclass.constructor.call(this, config);
970 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
978 getAutoCreate : function(){
981 tag: 'h' + (1 *this.level),
982 html: this.html || 'fill in html'
1000 * @class Roo.bootstrap.Menu
1001 * @extends Roo.bootstrap.Component
1002 * Bootstrap Menu class - container for MenuItems
1003 * @cfg {String} type type of menu
1007 * @param {Object} config The config object
1011 Roo.bootstrap.Menu = function(config){
1012 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1015 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1023 getChildContainer : function() {
1027 getAutoCreate : function(){
1029 //if (['right'].indexOf(this.align)!==-1) {
1030 // cfg.cn[1].cls += ' pull-right'
1034 cls : 'dropdown-menu'
1038 if (this.type==='submenu') {
1039 cfg.cls='submenu active'
1044 initEvents : function() {
1045 // Roo.log("ADD event");
1046 // Roo.log(this.triggerEl.dom);
1047 this.triggerEl.on('click', this.toggle, this);
1048 this.triggerEl.addClass('dropdown-toggle');
1051 toggle : function(e)
1053 //Roo.log(e.getTarget());
1054 // Roo.log(this.triggerEl.dom);
1055 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1058 var isActive = this.triggerEl.hasClass('open');
1059 // if disabled.. ingore
1061 //if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
1062 // if mobile we use a backdrop because click events don't delegate
1063 // $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
1066 //var relatedTarget = { relatedTarget: this }
1067 //$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
1069 //if (e.isDefaultPrevented()) return;
1071 this.triggerEl[isActive ? 'removeClass' : 'addClass']('open');
1073 // .trigger('shown.bs.dropdown', relatedTarget)
1075 this.triggerEl.focus();
1081 clearMenus : function()
1083 //$(backdrop).remove()
1084 Roo.select('.dropdown-toggle',true).each(function(aa) {
1085 if (!aa.hasClass('open')) {
1089 aa.removeClass('open');
1090 //var parent = getParent($(this))
1091 //var relatedTarget = { relatedTarget: this }
1093 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1094 //if (e.isDefaultPrevented()) return
1095 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1113 * @class Roo.bootstrap.MenuItem
1114 * @extends Roo.bootstrap.Component
1115 * Bootstrap MenuItem class
1116 * @cfg {String} html the menu label
1117 * @cfg {String} href the link
1118 * @cfg {Boolean} preventDefault (true | false) default true
1122 * Create a new MenuItem
1123 * @param {Object} config The config object
1127 Roo.bootstrap.MenuItem = function(config){
1128 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1133 * The raw click event for the entire grid.
1134 * @param {Roo.EventObject} e
1140 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1144 preventDefault: true,
1146 getAutoCreate : function(){
1158 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1159 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1163 initEvents: function() {
1165 this.el.on('click', this.onClick, this);
1168 onClick : function(e)
1170 Roo.log('item on click ');
1171 if(this.preventDefault){
1175 this.fireEvent('click', this, e);
1191 * @class Roo.bootstrap.MenuSeparator
1192 * @extends Roo.bootstrap.Component
1193 * Bootstrap MenuSeparator class
1196 * Create a new MenuItem
1197 * @param {Object} config The config object
1201 Roo.bootstrap.MenuSeparator = function(config){
1202 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1205 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1207 getAutoCreate : function(){
1222 <div class="modal fade">
1223 <div class="modal-dialog">
1224 <div class="modal-content">
1225 <div class="modal-header">
1226 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1227 <h4 class="modal-title">Modal title</h4>
1229 <div class="modal-body">
1230 <p>One fine body…</p>
1232 <div class="modal-footer">
1233 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1234 <button type="button" class="btn btn-primary">Save changes</button>
1236 </div><!-- /.modal-content -->
1237 </div><!-- /.modal-dialog -->
1238 </div><!-- /.modal -->
1248 * @class Roo.bootstrap.Modal
1249 * @extends Roo.bootstrap.Component
1250 * Bootstrap Modal class
1251 * @cfg {String} title Title of dialog
1252 * @cfg {Array} buttons Array of buttons or standard button set..
1255 * Create a new Modal Dialog
1256 * @param {Object} config The config object
1259 Roo.bootstrap.Modal = function(config){
1260 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1265 * The raw btnclick event for the button
1266 * @param {Roo.EventObject} e
1272 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1274 title : 'test dialog',
1278 onRender : function(ct, position)
1280 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1283 var cfg = Roo.apply({}, this.getAutoCreate());
1286 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1288 //if (!cfg.name.length) {
1292 cfg.cls += ' ' + this.cls;
1295 cfg.style = this.style;
1297 this.el = Roo.get(document.body).createChild(cfg, position);
1299 //var type = this.el.dom.type;
1301 if(this.tabIndex !== undefined){
1302 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1307 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1308 this.maskEl.enableDisplayMode("block");
1310 //this.el.addClass("x-dlg-modal");
1313 Roo.each(this.buttons, function(bb) {
1314 b = Roo.apply({}, bb);
1315 b.xns = b.xns || Roo.bootstrap;
1316 b.xtype = b.xtype || 'Button';
1317 if (typeof(b.listeners) == 'undefined') {
1318 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1321 var btn = Roo.factory(b);
1323 btn.onRender(this.el.select('.modal-footer').first());
1327 // render the children.
1330 if(typeof(this.items) != 'undefined'){
1331 var items = this.items;
1334 for(var i =0;i < items.length;i++) {
1335 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1339 this.items = nitems;
1341 //this.el.addClass([this.fieldClass, this.cls]);
1344 getAutoCreate : function(){
1349 html : this.html || ''
1357 cls: "modal-dialog",
1360 cls : "modal-content",
1363 cls : 'modal-header',
1372 cls : 'modal-title',
1380 cls : 'modal-footer'
1396 getChildContainer : function() {
1398 return this.el.select('.modal-body',true).first();
1401 getButtonContainer : function() {
1402 return this.el.select('.modal-footer',true).first();
1405 initEvents : function()
1407 this.el.select('.modal-header .close').on('click', this.hide, this);
1409 // this.addxtype(this);
1413 if (!this.rendered) {
1417 this.el.addClass('on');
1418 this.el.removeClass('fade');
1419 this.el.setStyle('display', 'block');
1420 Roo.get(document.body).addClass("x-body-masked");
1421 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1423 this.el.setStyle('zIndex', '10001');
1424 this.fireEvent('show', this);
1430 Roo.log('Modal hide?!');
1432 Roo.get(document.body).removeClass("x-body-masked");
1433 this.el.removeClass('on');
1434 this.el.addClass('fade');
1435 this.el.setStyle('display', 'none');
1436 this.fireEvent('hide', this);
1438 onButtonClick: function(btn,e)
1441 this.fireEvent('btnclick', btn.name, e);
1446 Roo.apply(Roo.bootstrap.Modal, {
1448 * Button config that displays a single OK button
1457 * Button config that displays Yes and No buttons
1473 * Button config that displays OK and Cancel buttons
1488 * Button config that displays Yes, No and Cancel buttons
1515 * @class Roo.bootstrap.Navbar
1516 * @extends Roo.bootstrap.Component
1517 * Bootstrap Navbar class
1518 * @cfg {Boolean} sidebar has side bar
1519 * @cfg {Boolean} bar is a bar?
1520 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
1521 * @cfg {String} brand what is brand
1522 * @cfg {Boolean} inverse is inverted color
1523 * @cfg {String} type (nav | pills | tabs)
1524 * @cfg {Boolean} arrangement stacked | justified
1525 * @cfg {String} align (left | right) alignment
1526 * @cfg {String} brand_href href of the brand
1527 * @cfg {Boolean} main (true|false) main nav bar? default false
1531 * Create a new Navbar
1532 * @param {Object} config The config object
1536 Roo.bootstrap.Navbar = function(config){
1537 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
1540 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
1554 getAutoCreate : function(){
1559 if (this.sidebar === true) {
1567 if (this.bar === true) {
1575 cls: 'navbar-header',
1580 cls: 'navbar-toggle',
1581 'data-toggle': 'collapse',
1586 html: 'Toggle navigation'
1606 cls: 'collapse navbar-collapse'
1611 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
1613 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
1614 cfg.cls += ' navbar-' + this.position;
1615 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
1618 if (this.brand !== '') {
1621 href: this.brand_href ? this.brand_href : '#',
1622 cls: 'navbar-brand',
1630 cfg.cls += ' main-nav';
1636 } else if (this.bar === false) {
1639 Roo.log('Property \'bar\' in of Navbar must be either true or false')
1649 if (['tabs','pills'].indexOf(this.type)!==-1) {
1650 cfg.cn[0].cls += ' nav-' + this.type
1652 if (this.type!=='nav') {
1653 Roo.log('nav type must be nav/tabs/pills')
1655 cfg.cn[0].cls += ' navbar-nav'
1658 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
1659 cfg.cn[0].cls += ' nav-' + this.arrangement;
1662 if (this.align === 'right') {
1663 cfg.cn[0].cls += ' navbar-right';
1666 cfg.cls += ' navbar-inverse';
1674 initEvents :function ()
1676 //Roo.log(this.el.select('.navbar-toggle',true));
1677 this.el.select('.navbar-toggle',true).on('click', function() {
1678 // Roo.log('click');
1679 this.el.select('.navbar-collapse',true).toggleClass('in');
1684 getChildContainer : function()
1686 if (this.bar === true) {
1687 return this.el.select('.collapse',true).first();
1705 * @class Roo.bootstrap.NavGroup
1706 * @extends Roo.bootstrap.Component
1707 * Bootstrap NavGroup class
1708 * @cfg {String} align left | right
1709 * @cfg {Boolean} inverse false | true
1710 * @cfg {String} type (nav|pills|tab) default nav
1713 * Create a new nav group
1714 * @param {Object} config The config object
1717 Roo.bootstrap.NavGroup = function(config){
1718 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
1721 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
1728 getAutoCreate : function(){
1729 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
1736 if (['tabs','pills'].indexOf(this.type)!==-1) {
1737 cfg.cls += ' nav-' + this.type
1739 if (this.type!=='nav') {
1740 Roo.log('nav type must be nav/tabs/pills')
1742 cfg.cls += ' navbar-nav'
1745 if (this.parent().sidebar === true) {
1748 cls: 'dashboard-menu'
1754 if (this.form === true) {
1760 if (this.align === 'right') {
1761 cfg.cls += ' navbar-right';
1763 cfg.cls += ' navbar-left';
1767 if (this.align === 'right') {
1768 cfg.cls += ' navbar-right';
1772 cfg.cls += ' navbar-inverse';
1792 * @class Roo.bootstrap.Navbar.Item
1793 * @extends Roo.bootstrap.Component
1794 * Bootstrap Navbar.Button class
1795 * @cfg {String} href link to
1796 * @cfg {String} html content of button
1797 * @cfg {String} badge text inside badge
1798 * @cfg {String} glyphicon name of glyphicon
1799 * @cfg {String} icon name of font awesome icon
1800 * @cfg {Boolena} active Is item active
1801 * @cfg {Boolean} preventDefault (true | false) default false
1804 * Create a new Navbar Button
1805 * @param {Object} config The config object
1807 Roo.bootstrap.Navbar.Item = function(config){
1808 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1813 * The raw click event for the entire grid.
1814 * @param {Roo.EventObject} e
1820 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
1829 preventDefault : false,
1831 getAutoCreate : function(){
1833 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1835 if (this.parent().parent().sidebar === true) {
1848 cfg.cn[0].html = this.html;
1852 this.cls += ' active';
1856 cfg.cn[0].cls += ' dropdown-toggle';
1857 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1861 cfg.cn[0].tag = 'a',
1862 cfg.cn[0].href = this.href;
1865 if (this.glyphicon) {
1866 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1870 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1882 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
1892 if (this.glyphicon) {
1893 if(cfg.html){cfg.html = ' ' + this.html};
1897 cls: 'glyphicon glyphicon-' + this.glyphicon
1902 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1907 cfg.cn[0].html += " <span class='caret'></span>";
1908 //}else if (!this.href) {
1909 // cfg.cn[0].tag='p';
1910 // cfg.cn[0].cls='navbar-text';
1913 cfg.cn[0].href=this.href||'#';
1914 cfg.cn[0].html=this.html;
1917 if (this.badge !== '') {
1920 cfg.cn[0].html + ' ',
1931 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1936 initEvents: function() {
1937 // Roo.log('init events?');
1938 // Roo.log(this.el.dom);
1939 this.el.select('a',true).on('click', this.onClick, this);
1942 onClick : function(e)
1944 if(this.preventDefault){
1948 if(this.fireEvent('click', this, e) === false){
1952 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
1953 this.onTabsClick(e);
1957 onTabsClick : function(e)
1959 Roo.each(this.parent().el.select('.active',true).elements, function(v){
1960 v.removeClass('active');
1963 this.el.addClass('active');
1965 if(this.href && this.href.substring(0,1) == '#'){
1966 var tab = Roo.select('[tabId=' + this.href + ']', true).first();
1968 Roo.each(tab.findParent('.tab-content', 0, true).select('.active', true).elements, function(v){
1969 v.removeClass('active');
1972 tab.addClass('active');
1987 * @class Roo.bootstrap.Row
1988 * @extends Roo.bootstrap.Component
1989 * Bootstrap Row class (contains columns...)
1993 * @param {Object} config The config object
1996 Roo.bootstrap.Row = function(config){
1997 Roo.bootstrap.Row.superclass.constructor.call(this, config);
2000 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
2002 getAutoCreate : function(){
2021 * @class Roo.bootstrap.Element
2022 * @extends Roo.bootstrap.Component
2023 * Bootstrap Element class
2024 * @cfg {String} html contents of the element
2025 * @cfg {String} tag tag of the element
2026 * @cfg {String} cls class of the element
2029 * Create a new Element
2030 * @param {Object} config The config object
2033 Roo.bootstrap.Element = function(config){
2034 Roo.bootstrap.Element.superclass.constructor.call(this, config);
2037 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
2044 getAutoCreate : function(){
2069 * @class Roo.bootstrap.Pagination
2070 * @extends Roo.bootstrap.Component
2071 * Bootstrap Pagination class
2072 * @cfg {String} size xs | sm | md | lg
2073 * @cfg {Boolean} inverse false | true
2076 * Create a new Pagination
2077 * @param {Object} config The config object
2080 Roo.bootstrap.Pagination = function(config){
2081 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
2084 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
2090 getAutoCreate : function(){
2096 cfg.cls += ' inverse';
2102 cfg.cls += " " + this.cls;
2120 * @class Roo.bootstrap.PaginationItem
2121 * @extends Roo.bootstrap.Component
2122 * Bootstrap PaginationItem class
2123 * @cfg {String} html text
2124 * @cfg {String} href the link
2125 * @cfg {Boolean} preventDefault (true | false) default true
2126 * @cfg {Boolean} active (true | false) default false
2130 * Create a new PaginationItem
2131 * @param {Object} config The config object
2135 Roo.bootstrap.PaginationItem = function(config){
2136 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
2141 * The raw click event for the entire grid.
2142 * @param {Roo.EventObject} e
2148 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
2152 preventDefault: true,
2156 getAutoCreate : function(){
2162 href : this.href ? this.href : '#',
2163 html : this.html ? this.html : ''
2173 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
2179 initEvents: function() {
2181 this.el.on('click', this.onClick, this);
2184 onClick : function(e)
2186 Roo.log('PaginationItem on click ');
2187 if(this.preventDefault){
2191 this.fireEvent('click', this, e);
2207 * @class Roo.bootstrap.Slider
2208 * @extends Roo.bootstrap.Component
2209 * Bootstrap Slider class
2212 * Create a new Slider
2213 * @param {Object} config The config object
2216 Roo.bootstrap.Slider = function(config){
2217 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
2220 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
2222 getAutoCreate : function(){
2226 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
2230 cls: 'ui-slider-handle ui-state-default ui-corner-all'
2248 * @class Roo.bootstrap.Table
2249 * @extends Roo.bootstrap.Component
2250 * Bootstrap Table class
2251 * @cfg {String} cls table class
2252 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
2253 * @cfg {String} bgcolor Specifies the background color for a table
2254 * @cfg {Number} border Specifies whether the table cells should have borders or not
2255 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
2256 * @cfg {Number} cellspacing Specifies the space between cells
2257 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
2258 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
2259 * @cfg {String} sortable Specifies that the table should be sortable
2260 * @cfg {String} summary Specifies a summary of the content of a table
2261 * @cfg {Number} width Specifies the width of a table
2263 * @cfg {boolean} striped Should the rows be alternative striped
2264 * @cfg {boolean} bordered Add borders to the table
2265 * @cfg {boolean} hover Add hover highlighting
2266 * @cfg {boolean} condensed Format condensed
2267 * @cfg {boolean} responsive Format condensed
2273 * Create a new Table
2274 * @param {Object} config The config object
2277 Roo.bootstrap.Table = function(config){
2278 Roo.bootstrap.Table.superclass.constructor.call(this, config);
2281 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
2282 this.sm = this.selModel;
2283 this.sm.xmodule = this.xmodule || false;
2285 if (this.cm && typeof(this.cm.config) == 'undefined') {
2286 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
2287 this.cm = this.colModel;
2288 this.cm.xmodule = this.xmodule || false;
2291 this.store= Roo.factory(this.store, Roo.data);
2292 this.ds = this.store;
2293 this.ds.xmodule = this.xmodule || false;
2298 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
2320 getAutoCreate : function(){
2321 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2330 cfg.cls += ' table-striped';
2333 cfg.cls += ' table-hover';
2335 if (this.bordered) {
2336 cfg.cls += ' table-bordered';
2338 if (this.condensed) {
2339 cfg.cls += ' table-condensed';
2341 if (this.responsive) {
2342 cfg.cls += ' table-responsive';
2349 cfg.cls+= ' ' +this.cls;
2352 // this lot should be simplifed...
2355 cfg.align=this.align;
2358 cfg.bgcolor=this.bgcolor;
2361 cfg.border=this.border;
2363 if (this.cellpadding) {
2364 cfg.cellpadding=this.cellpadding;
2366 if (this.cellspacing) {
2367 cfg.cellspacing=this.cellspacing;
2370 cfg.frame=this.frame;
2373 cfg.rules=this.rules;
2375 if (this.sortable) {
2376 cfg.sortable=this.sortable;
2379 cfg.summary=this.summary;
2382 cfg.width=this.width;
2385 if(this.store || this.cm){
2386 cfg.cn.push(this.renderHeader());
2387 cfg.cn.push(this.renderBody());
2388 cfg.cn.push(this.renderFooter());
2390 cfg.cls+= ' TableGrid';
2396 // initTableGrid : function()
2405 // var cm = this.cm;
2407 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
2410 // html: cm.getColumnHeader(i)
2414 // cfg.push(header);
2421 initEvents : function()
2423 if(!this.store || !this.cm){
2427 Roo.log('initEvents with ds!!!!');
2429 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
2430 // this.maskEl.enableDisplayMode("block");
2431 // this.maskEl.show();
2433 this.store.on('load', this.onLoad, this);
2434 this.store.on('beforeload', this.onBeforeLoad, this);
2442 renderHeader : function()
2451 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
2454 html: cm.getColumnHeader(i)
2461 renderBody : function()
2471 renderFooter : function()
2483 Roo.log('ds onload');
2487 var tbody = this.el.select('tbody', true).first();
2491 if(this.store.getCount() > 0){
2492 this.store.data.each(function(d){
2498 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
2499 var renderer = cm.getRenderer(i);
2503 if(typeof(renderer) !== 'undefined'){
2504 value = renderer(d.data[cm.getDataIndex(i)], false, d);
2507 if(typeof(value) === 'object'){
2517 html: (typeof(value) === 'object') ? '' : value
2522 tbody.createChild(row);
2528 Roo.each(renders, function(r){
2529 r.cfg.render(Roo.get(r.id));
2533 // if(this.loadMask){
2534 // this.maskEl.hide();
2538 onBeforeLoad : function()
2540 Roo.log('ds onBeforeLoad');
2544 // if(this.loadMask){
2545 // this.maskEl.show();
2551 this.el.select('tbody', true).first().dom.innerHTML = '';
2554 getSelectionModel : function(){
2556 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
2558 return this.selModel;
2573 * @class Roo.bootstrap.TableCell
2574 * @extends Roo.bootstrap.Component
2575 * Bootstrap TableCell class
2576 * @cfg {String} html cell contain text
2577 * @cfg {String} cls cell class
2578 * @cfg {String} tag cell tag (td|th) default td
2579 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
2580 * @cfg {String} align Aligns the content in a cell
2581 * @cfg {String} axis Categorizes cells
2582 * @cfg {String} bgcolor Specifies the background color of a cell
2583 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
2584 * @cfg {Number} colspan Specifies the number of columns a cell should span
2585 * @cfg {String} headers Specifies one or more header cells a cell is related to
2586 * @cfg {Number} height Sets the height of a cell
2587 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
2588 * @cfg {Number} rowspan Sets the number of rows a cell should span
2589 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
2590 * @cfg {String} valign Vertical aligns the content in a cell
2591 * @cfg {Number} width Specifies the width of a cell
2594 * Create a new TableCell
2595 * @param {Object} config The config object
2598 Roo.bootstrap.TableCell = function(config){
2599 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
2602 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
2622 getAutoCreate : function(){
2623 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
2643 cfg.align=this.align
2649 cfg.bgcolor=this.bgcolor
2652 cfg.charoff=this.charoff
2655 cfg.colspan=this.colspan
2658 cfg.headers=this.headers
2661 cfg.height=this.height
2664 cfg.nowrap=this.nowrap
2667 cfg.rowspan=this.rowspan
2670 cfg.scope=this.scope
2673 cfg.valign=this.valign
2676 cfg.width=this.width
2695 * @class Roo.bootstrap.TableRow
2696 * @extends Roo.bootstrap.Component
2697 * Bootstrap TableRow class
2698 * @cfg {String} cls row class
2699 * @cfg {String} align Aligns the content in a table row
2700 * @cfg {String} bgcolor Specifies a background color for a table row
2701 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
2702 * @cfg {String} valign Vertical aligns the content in a table row
2705 * Create a new TableRow
2706 * @param {Object} config The config object
2709 Roo.bootstrap.TableRow = function(config){
2710 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2713 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
2721 getAutoCreate : function(){
2722 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2732 cfg.align = this.align;
2735 cfg.bgcolor = this.bgcolor;
2738 cfg.charoff = this.charoff;
2741 cfg.valign = this.valign;
2759 * @class Roo.bootstrap.TableBody
2760 * @extends Roo.bootstrap.Component
2761 * Bootstrap TableBody class
2762 * @cfg {String} cls element class
2763 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
2764 * @cfg {String} align Aligns the content inside the element
2765 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
2766 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
2769 * Create a new TableBody
2770 * @param {Object} config The config object
2773 Roo.bootstrap.TableBody = function(config){
2774 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
2777 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
2785 getAutoCreate : function(){
2786 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
2800 cfg.align = this.align;
2803 cfg.charoff = this.charoff;
2806 cfg.valign = this.valign;
2813 // initEvents : function()
2820 // this.store = Roo.factory(this.store, Roo.data);
2821 // this.store.on('load', this.onLoad, this);
2823 // this.store.load();
2827 // onLoad: function ()
2829 // this.fireEvent('load', this);
2839 * Ext JS Library 1.1.1
2840 * Copyright(c) 2006-2007, Ext JS, LLC.
2842 * Originally Released Under LGPL - original licence link has changed is not relivant.
2845 * <script type="text/javascript">
2848 // as we use this in bootstrap.
2849 Roo.namespace('Roo.form');
2851 * @class Roo.form.Action
2852 * Internal Class used to handle form actions
2854 * @param {Roo.form.BasicForm} el The form element or its id
2855 * @param {Object} config Configuration options
2860 // define the action interface
2861 Roo.form.Action = function(form, options){
2863 this.options = options || {};
2866 * Client Validation Failed
2869 Roo.form.Action.CLIENT_INVALID = 'client';
2871 * Server Validation Failed
2874 Roo.form.Action.SERVER_INVALID = 'server';
2876 * Connect to Server Failed
2879 Roo.form.Action.CONNECT_FAILURE = 'connect';
2881 * Reading Data from Server Failed
2884 Roo.form.Action.LOAD_FAILURE = 'load';
2886 Roo.form.Action.prototype = {
2888 failureType : undefined,
2889 response : undefined,
2893 run : function(options){
2898 success : function(response){
2903 handleResponse : function(response){
2907 // default connection failure
2908 failure : function(response){
2910 this.response = response;
2911 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2912 this.form.afterAction(this, false);
2915 processResponse : function(response){
2916 this.response = response;
2917 if(!response.responseText){
2920 this.result = this.handleResponse(response);
2924 // utility functions used internally
2925 getUrl : function(appendParams){
2926 var url = this.options.url || this.form.url || this.form.el.dom.action;
2928 var p = this.getParams();
2930 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2936 getMethod : function(){
2937 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2940 getParams : function(){
2941 var bp = this.form.baseParams;
2942 var p = this.options.params;
2944 if(typeof p == "object"){
2945 p = Roo.urlEncode(Roo.applyIf(p, bp));
2946 }else if(typeof p == 'string' && bp){
2947 p += '&' + Roo.urlEncode(bp);
2950 p = Roo.urlEncode(bp);
2955 createCallback : function(){
2957 success: this.success,
2958 failure: this.failure,
2960 timeout: (this.form.timeout*1000),
2961 upload: this.form.fileUpload ? this.success : undefined
2966 Roo.form.Action.Submit = function(form, options){
2967 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
2970 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
2973 haveProgress : false,
2974 uploadComplete : false,
2976 // uploadProgress indicator.
2977 uploadProgress : function()
2979 if (!this.form.progressUrl) {
2983 if (!this.haveProgress) {
2984 Roo.MessageBox.progress("Uploading", "Uploading");
2986 if (this.uploadComplete) {
2987 Roo.MessageBox.hide();
2991 this.haveProgress = true;
2993 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
2995 var c = new Roo.data.Connection();
2997 url : this.form.progressUrl,
3002 success : function(req){
3003 //console.log(data);
3007 rdata = Roo.decode(req.responseText)
3009 Roo.log("Invalid data from server..");
3013 if (!rdata || !rdata.success) {
3015 Roo.MessageBox.alert(Roo.encode(rdata));
3018 var data = rdata.data;
3020 if (this.uploadComplete) {
3021 Roo.MessageBox.hide();
3026 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
3027 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
3030 this.uploadProgress.defer(2000,this);
3033 failure: function(data) {
3034 Roo.log('progress url failed ');
3045 // run get Values on the form, so it syncs any secondary forms.
3046 this.form.getValues();
3048 var o = this.options;
3049 var method = this.getMethod();
3050 var isPost = method == 'POST';
3051 if(o.clientValidation === false || this.form.isValid()){
3053 if (this.form.progressUrl) {
3054 this.form.findField('UPLOAD_IDENTIFIER').setValue(
3055 (new Date() * 1) + '' + Math.random());
3060 Roo.Ajax.request(Roo.apply(this.createCallback(), {
3061 form:this.form.el.dom,
3062 url:this.getUrl(!isPost),
3064 params:isPost ? this.getParams() : null,
3065 isUpload: this.form.fileUpload
3068 this.uploadProgress();
3070 }else if (o.clientValidation !== false){ // client validation failed
3071 this.failureType = Roo.form.Action.CLIENT_INVALID;
3072 this.form.afterAction(this, false);
3076 success : function(response)
3078 this.uploadComplete= true;
3079 if (this.haveProgress) {
3080 Roo.MessageBox.hide();
3084 var result = this.processResponse(response);
3085 if(result === true || result.success){
3086 this.form.afterAction(this, true);
3090 this.form.markInvalid(result.errors);
3091 this.failureType = Roo.form.Action.SERVER_INVALID;
3093 this.form.afterAction(this, false);
3095 failure : function(response)
3097 this.uploadComplete= true;
3098 if (this.haveProgress) {
3099 Roo.MessageBox.hide();
3102 this.response = response;
3103 this.failureType = Roo.form.Action.CONNECT_FAILURE;
3104 this.form.afterAction(this, false);
3107 handleResponse : function(response){
3108 if(this.form.errorReader){
3109 var rs = this.form.errorReader.read(response);
3112 for(var i = 0, len = rs.records.length; i < len; i++) {
3113 var r = rs.records[i];
3117 if(errors.length < 1){
3121 success : rs.success,
3127 ret = Roo.decode(response.responseText);
3131 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
3141 Roo.form.Action.Load = function(form, options){
3142 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
3143 this.reader = this.form.reader;
3146 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
3151 Roo.Ajax.request(Roo.apply(
3152 this.createCallback(), {
3153 method:this.getMethod(),
3154 url:this.getUrl(false),
3155 params:this.getParams()
3159 success : function(response){
3161 var result = this.processResponse(response);
3162 if(result === true || !result.success || !result.data){
3163 this.failureType = Roo.form.Action.LOAD_FAILURE;
3164 this.form.afterAction(this, false);
3167 this.form.clearInvalid();
3168 this.form.setValues(result.data);
3169 this.form.afterAction(this, true);
3172 handleResponse : function(response){
3173 if(this.form.reader){
3174 var rs = this.form.reader.read(response);
3175 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
3177 success : rs.success,
3181 return Roo.decode(response.responseText);
3185 Roo.form.Action.ACTION_TYPES = {
3186 'load' : Roo.form.Action.Load,
3187 'submit' : Roo.form.Action.Submit
3196 * @class Roo.bootstrap.Form
3197 * @extends Roo.bootstrap.Component
3198 * Bootstrap Form class
3199 * @cfg {String} method GET | POST (default POST)
3200 * @cfg {String} labelAlign top | left (default top)
3201 * @cfg {String} align left | right - for navbars
3206 * @param {Object} config The config object
3210 Roo.bootstrap.Form = function(config){
3211 Roo.bootstrap.Form.superclass.constructor.call(this, config);
3214 * @event clientvalidation
3215 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
3216 * @param {Form} this
3217 * @param {Boolean} valid true if the form has passed client-side validation
3219 clientvalidation: true,
3221 * @event beforeaction
3222 * Fires before any action is performed. Return false to cancel the action.
3223 * @param {Form} this
3224 * @param {Action} action The action to be performed
3228 * @event actionfailed
3229 * Fires when an action fails.
3230 * @param {Form} this
3231 * @param {Action} action The action that failed
3233 actionfailed : true,
3235 * @event actioncomplete
3236 * Fires when an action is completed.
3237 * @param {Form} this
3238 * @param {Action} action The action that completed
3240 actioncomplete : true
3245 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
3248 * @cfg {String} method
3249 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
3254 * The URL to use for form actions if one isn't supplied in the action options.
3257 * @cfg {Boolean} fileUpload
3258 * Set to true if this form is a file upload.
3262 * @cfg {Object} baseParams
3263 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
3267 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
3271 * @cfg {Sting} align (left|right) for navbar forms
3276 activeAction : null,
3279 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3280 * element by passing it or its id or mask the form itself by passing in true.
3283 waitMsgTarget : false,
3288 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3289 * element by passing it or its id or mask the form itself by passing in true.
3293 getAutoCreate : function(){
3297 method : this.method || 'POST',
3298 id : this.id || Roo.id(),
3301 if (this.parent().xtype.match(/^Nav/)) {
3302 cfg.cls = 'navbar-form navbar-' + this.align;
3306 if (this.labelAlign == 'left' ) {
3307 cfg.cls += ' form-horizontal';
3313 initEvents : function()
3315 this.el.on('submit', this.onSubmit, this);
3320 onSubmit : function(e){
3325 * Returns true if client-side validation on the form is successful.
3328 isValid : function(){
3329 var items = this.getItems();
3331 items.each(function(f){
3340 * Returns true if any fields in this form have changed since their original load.
3343 isDirty : function(){
3345 var items = this.getItems();
3346 items.each(function(f){
3356 * Performs a predefined action (submit or load) or custom actions you define on this form.
3357 * @param {String} actionName The name of the action type
3358 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
3359 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
3360 * accept other config options):
3362 Property Type Description
3363 ---------------- --------------- ----------------------------------------------------------------------------------
3364 url String The url for the action (defaults to the form's url)
3365 method String The form method to use (defaults to the form's method, or POST if not defined)
3366 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
3367 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
3368 validate the form on the client (defaults to false)
3370 * @return {BasicForm} this
3372 doAction : function(action, options){
3373 if(typeof action == 'string'){
3374 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
3376 if(this.fireEvent('beforeaction', this, action) !== false){
3377 this.beforeAction(action);
3378 action.run.defer(100, action);
3384 beforeAction : function(action){
3385 var o = action.options;
3387 // not really supported yet.. ??
3389 //if(this.waitMsgTarget === true){
3390 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
3391 //}else if(this.waitMsgTarget){
3392 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
3393 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
3395 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
3401 afterAction : function(action, success){
3402 this.activeAction = null;
3403 var o = action.options;
3405 //if(this.waitMsgTarget === true){
3407 //}else if(this.waitMsgTarget){
3408 // this.waitMsgTarget.unmask();
3410 // Roo.MessageBox.updateProgress(1);
3411 // Roo.MessageBox.hide();
3418 Roo.callback(o.success, o.scope, [this, action]);
3419 this.fireEvent('actioncomplete', this, action);
3423 // failure condition..
3424 // we have a scenario where updates need confirming.
3425 // eg. if a locking scenario exists..
3426 // we look for { errors : { needs_confirm : true }} in the response.
3428 (typeof(action.result) != 'undefined') &&
3429 (typeof(action.result.errors) != 'undefined') &&
3430 (typeof(action.result.errors.needs_confirm) != 'undefined')
3433 Roo.log("not supported yet");
3436 Roo.MessageBox.confirm(
3437 "Change requires confirmation",
3438 action.result.errorMsg,
3443 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
3453 Roo.callback(o.failure, o.scope, [this, action]);
3454 // show an error message if no failed handler is set..
3455 if (!this.hasListener('actionfailed')) {
3456 Roo.log("need to add dialog support");
3458 Roo.MessageBox.alert("Error",
3459 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
3460 action.result.errorMsg :
3461 "Saving Failed, please check your entries or try again"
3466 this.fireEvent('actionfailed', this, action);
3471 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
3472 * @param {String} id The value to search for
3475 findField : function(id){
3476 var items = this.getItems();
3477 var field = items.get(id);
3479 items.each(function(f){
3480 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
3487 return field || null;
3490 * Mark fields in this form invalid in bulk.
3491 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
3492 * @return {BasicForm} this
3494 markInvalid : function(errors){
3495 if(errors instanceof Array){
3496 for(var i = 0, len = errors.length; i < len; i++){
3497 var fieldError = errors[i];
3498 var f = this.findField(fieldError.id);
3500 f.markInvalid(fieldError.msg);
3506 if(typeof errors[id] != 'function' && (field = this.findField(id))){
3507 field.markInvalid(errors[id]);
3511 //Roo.each(this.childForms || [], function (f) {
3512 // f.markInvalid(errors);
3519 * Set values for fields in this form in bulk.
3520 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
3521 * @return {BasicForm} this
3523 setValues : function(values){
3524 if(values instanceof Array){ // array of objects
3525 for(var i = 0, len = values.length; i < len; i++){
3527 var f = this.findField(v.id);
3529 f.setValue(v.value);
3530 if(this.trackResetOnLoad){
3531 f.originalValue = f.getValue();
3535 }else{ // object hash
3538 if(typeof values[id] != 'function' && (field = this.findField(id))){
3540 if (field.setFromData &&
3542 field.displayField &&
3543 // combos' with local stores can
3544 // be queried via setValue()
3545 // to set their value..
3546 (field.store && !field.store.isLocal)
3550 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
3551 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
3552 field.setFromData(sd);
3555 field.setValue(values[id]);
3559 if(this.trackResetOnLoad){
3560 field.originalValue = field.getValue();
3566 //Roo.each(this.childForms || [], function (f) {
3567 // f.setValues(values);
3574 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
3575 * they are returned as an array.
3576 * @param {Boolean} asString
3579 getValues : function(asString){
3580 //if (this.childForms) {
3581 // copy values from the child forms
3582 // Roo.each(this.childForms, function (f) {
3583 // this.setValues(f.getValues());
3589 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
3590 if(asString === true){
3593 return Roo.urlDecode(fs);
3597 * Returns the fields in this form as an object with key/value pairs.
3598 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
3601 getFieldValues : function(with_hidden)
3603 var items = this.getItems();
3605 items.each(function(f){
3609 var v = f.getValue();
3610 if (f.inputType =='radio') {
3611 if (typeof(ret[f.getName()]) == 'undefined') {
3612 ret[f.getName()] = ''; // empty..
3615 if (!f.el.dom.checked) {
3623 // not sure if this supported any more..
3624 if ((typeof(v) == 'object') && f.getRawValue) {
3625 v = f.getRawValue() ; // dates..
3627 // combo boxes where name != hiddenName...
3628 if (f.name != f.getName()) {
3629 ret[f.name] = f.getRawValue();
3631 ret[f.getName()] = v;
3638 * Clears all invalid messages in this form.
3639 * @return {BasicForm} this
3641 clearInvalid : function(){
3642 var items = this.getItems();
3644 items.each(function(f){
3655 * @return {BasicForm} this
3658 var items = this.getItems();
3659 items.each(function(f){
3663 Roo.each(this.childForms || [], function (f) {
3670 getItems : function()
3672 var r=new Roo.util.MixedCollection(false, function(o){
3673 return o.id || (o.id = Roo.id());
3675 var iter = function(el) {
3682 Roo.each(el.items,function(e) {
3701 * Ext JS Library 1.1.1
3702 * Copyright(c) 2006-2007, Ext JS, LLC.
3704 * Originally Released Under LGPL - original licence link has changed is not relivant.
3707 * <script type="text/javascript">
3710 * @class Roo.form.VTypes
3711 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
3714 Roo.form.VTypes = function(){
3715 // closure these in so they are only created once.
3716 var alpha = /^[a-zA-Z_]+$/;
3717 var alphanum = /^[a-zA-Z0-9_]+$/;
3718 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
3719 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
3721 // All these messages and functions are configurable
3724 * The function used to validate email addresses
3725 * @param {String} value The email address
3727 'email' : function(v){
3728 return email.test(v);
3731 * The error text to display when the email validation function returns false
3734 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
3736 * The keystroke filter mask to be applied on email input
3739 'emailMask' : /[a-z0-9_\.\-@]/i,
3742 * The function used to validate URLs
3743 * @param {String} value The URL
3745 'url' : function(v){
3749 * The error text to display when the url validation function returns false
3752 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
3755 * The function used to validate alpha values
3756 * @param {String} value The value
3758 'alpha' : function(v){
3759 return alpha.test(v);
3762 * The error text to display when the alpha validation function returns false
3765 'alphaText' : 'This field should only contain letters and _',
3767 * The keystroke filter mask to be applied on alpha input
3770 'alphaMask' : /[a-z_]/i,
3773 * The function used to validate alphanumeric values
3774 * @param {String} value The value
3776 'alphanum' : function(v){
3777 return alphanum.test(v);
3780 * The error text to display when the alphanumeric validation function returns false
3783 'alphanumText' : 'This field should only contain letters, numbers and _',
3785 * The keystroke filter mask to be applied on alphanumeric input
3788 'alphanumMask' : /[a-z0-9_]/i
3798 * @class Roo.bootstrap.Input
3799 * @extends Roo.bootstrap.Component
3800 * Bootstrap Input class
3801 * @cfg {Boolean} disabled is it disabled
3802 * @cfg {String} fieldLabel - the label associated
3803 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3804 * @cfg {String} name name of the input
3805 * @cfg {string} fieldLabel - the label associated
3806 * @cfg {string} inputType - input / file submit ...
3807 * @cfg {string} placeholder - placeholder to put in text.
3808 * @cfg {string} before - input group add on before
3809 * @cfg {string} after - input group add on after
3810 * @cfg {string} size - (lg|sm) or leave empty..
3811 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3812 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3813 * @cfg {Number} md colspan out of 12 for computer-sized screens
3814 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3815 * @cfg {string} value default value of the input
3816 * @cfg {Number} labelWidth set the width of label (0-12)
3817 * @cfg {String} labelAlign (top|left)
3821 * Create a new Input
3822 * @param {Object} config The config object
3825 Roo.bootstrap.Input = function(config){
3826 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3831 * Fires when this field receives input focus.
3832 * @param {Roo.form.Field} this
3837 * Fires when this field loses input focus.
3838 * @param {Roo.form.Field} this
3843 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3844 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3845 * @param {Roo.form.Field} this
3846 * @param {Roo.EventObject} e The event object
3851 * Fires just before the field blurs if the field value has changed.
3852 * @param {Roo.form.Field} this
3853 * @param {Mixed} newValue The new value
3854 * @param {Mixed} oldValue The original value
3859 * Fires after the field has been marked as invalid.
3860 * @param {Roo.form.Field} this
3861 * @param {String} msg The validation message
3866 * Fires after the field has been validated with no errors.
3867 * @param {Roo.form.Field} this
3872 * Fires after the key up
3873 * @param {Roo.form.Field} this
3874 * @param {Roo.EventObject} e The event Object
3880 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3882 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3883 automatic validation (defaults to "keyup").
3885 validationEvent : "keyup",
3887 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3889 validateOnBlur : true,
3891 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3893 validationDelay : 250,
3895 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3897 focusClass : "x-form-focus", // not needed???
3901 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3903 invalidClass : "has-error",
3906 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3908 selectOnFocus : false,
3911 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3915 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3920 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3922 disableKeyFilter : false,
3925 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3929 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3933 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3935 blankText : "This field is required",
3938 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3942 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3944 maxLength : Number.MAX_VALUE,
3946 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3948 minLengthText : "The minimum length for this field is {0}",
3950 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3952 maxLengthText : "The maximum length for this field is {0}",
3956 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3957 * If available, this function will be called only after the basic validators all return true, and will be passed the
3958 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3962 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3963 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3964 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
3968 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3990 parentLabelAlign : function()
3993 while (parent.parent()) {
3994 parent = parent.parent();
3995 if (typeof(parent.labelAlign) !='undefined') {
3996 return parent.labelAlign;
4003 getAutoCreate : function(){
4005 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4011 if(this.inputType != 'hidden'){
4012 cfg.cls = 'form-group' //input-group
4018 type : this.inputType,
4020 cls : 'form-control',
4021 placeholder : this.placeholder || ''
4025 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4026 input.maxLength = this.maxLength;
4029 if (this.disabled) {
4030 input.disabled=true;
4034 input.name = this.name;
4037 input.cls += ' input-' + this.size;
4040 ['xs','sm','md','lg'].map(function(size){
4041 if (settings[size]) {
4042 cfg.cls += ' col-' + size + '-' + settings[size];
4046 var inputblock = input;
4048 if (this.before || this.after) {
4051 cls : 'input-group',
4055 inputblock.cn.push({
4057 cls : 'input-group-addon',
4061 inputblock.cn.push(input);
4063 inputblock.cn.push({
4065 cls : 'input-group-addon',
4072 if (align ==='left' && this.fieldLabel.length) {
4073 Roo.log("left and has label");
4079 cls : 'control-label col-sm-' + this.labelWidth,
4080 html : this.fieldLabel
4084 cls : "col-sm-" + (12 - this.labelWidth),
4091 } else if ( this.fieldLabel.length) {
4097 //cls : 'input-group-addon',
4098 html : this.fieldLabel
4108 Roo.log(" no label && no align");
4122 * return the real input element.
4124 inputEl: function ()
4126 return this.el.select('input.form-control',true).first();
4128 setDisabled : function(v)
4130 var i = this.inputEl().dom;
4132 i.removeAttribute('disabled');
4136 i.setAttribute('disabled','true');
4138 initEvents : function()
4141 this.inputEl().on("keydown" , this.fireKey, this);
4142 this.inputEl().on("focus", this.onFocus, this);
4143 this.inputEl().on("blur", this.onBlur, this);
4145 this.inputEl().relayEvent('keyup', this);
4147 // reference to original value for reset
4148 this.originalValue = this.getValue();
4149 //Roo.form.TextField.superclass.initEvents.call(this);
4150 if(this.validationEvent == 'keyup'){
4151 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
4152 this.inputEl().on('keyup', this.filterValidation, this);
4154 else if(this.validationEvent !== false){
4155 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
4158 if(this.selectOnFocus){
4159 this.on("focus", this.preFocus, this);
4162 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
4163 this.inputEl().on("keypress", this.filterKeys, this);
4166 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
4167 this.el.on("click", this.autoSize, this);
4170 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
4171 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
4175 filterValidation : function(e){
4176 if(!e.isNavKeyPress()){
4177 this.validationTask.delay(this.validationDelay);
4181 * Validates the field value
4182 * @return {Boolean} True if the value is valid, else false
4184 validate : function(){
4185 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
4186 if(this.disabled || this.validateValue(this.getRawValue())){
4187 this.clearInvalid();
4195 * Validates a value according to the field's validation rules and marks the field as invalid
4196 * if the validation fails
4197 * @param {Mixed} value The value to validate
4198 * @return {Boolean} True if the value is valid, else false
4200 validateValue : function(value){
4201 if(value.length < 1) { // if it's blank
4202 if(this.allowBlank){
4203 this.clearInvalid();
4206 this.markInvalid(this.blankText);
4210 if(value.length < this.minLength){
4211 this.markInvalid(String.format(this.minLengthText, this.minLength));
4214 if(value.length > this.maxLength){
4215 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
4219 var vt = Roo.form.VTypes;
4220 if(!vt[this.vtype](value, this)){
4221 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
4225 if(typeof this.validator == "function"){
4226 var msg = this.validator(value);
4228 this.markInvalid(msg);
4232 if(this.regex && !this.regex.test(value)){
4233 this.markInvalid(this.regexText);
4242 fireKey : function(e){
4243 //Roo.log('field ' + e.getKey());
4244 if(e.isNavKeyPress()){
4245 this.fireEvent("specialkey", this, e);
4248 focus : function (selectText){
4250 this.inputEl().focus();
4251 if(selectText === true){
4252 this.inputEl().dom.select();
4258 onFocus : function(){
4259 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4260 // this.el.addClass(this.focusClass);
4263 this.hasFocus = true;
4264 this.startValue = this.getValue();
4265 this.fireEvent("focus", this);
4269 beforeBlur : Roo.emptyFn,
4273 onBlur : function(){
4275 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4276 //this.el.removeClass(this.focusClass);
4278 this.hasFocus = false;
4279 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
4282 var v = this.getValue();
4283 if(String(v) !== String(this.startValue)){
4284 this.fireEvent('change', this, v, this.startValue);
4286 this.fireEvent("blur", this);
4290 * Resets the current field value to the originally loaded value and clears any validation messages
4293 this.setValue(this.originalValue);
4294 this.clearInvalid();
4297 * Returns the name of the field
4298 * @return {Mixed} name The name field
4300 getName: function(){
4304 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
4305 * @return {Mixed} value The field value
4307 getValue : function(){
4308 return this.inputEl().getValue();
4311 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
4312 * @return {Mixed} value The field value
4314 getRawValue : function(){
4315 var v = this.inputEl().getValue();
4321 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
4322 * @param {Mixed} value The value to set
4324 setRawValue : function(v){
4325 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4328 selectText : function(start, end){
4329 var v = this.getRawValue();
4331 start = start === undefined ? 0 : start;
4332 end = end === undefined ? v.length : end;
4333 var d = this.inputEl().dom;
4334 if(d.setSelectionRange){
4335 d.setSelectionRange(start, end);
4336 }else if(d.createTextRange){
4337 var range = d.createTextRange();
4338 range.moveStart("character", start);
4339 range.moveEnd("character", v.length-end);
4346 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
4347 * @param {Mixed} value The value to set
4349 setValue : function(v){
4352 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4358 processValue : function(value){
4359 if(this.stripCharsRe){
4360 var newValue = value.replace(this.stripCharsRe, '');
4361 if(newValue !== value){
4362 this.setRawValue(newValue);
4369 preFocus : function(){
4371 if(this.selectOnFocus){
4372 this.inputEl().dom.select();
4375 filterKeys : function(e){
4377 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
4380 var c = e.getCharCode(), cc = String.fromCharCode(c);
4381 if(Roo.isIE && (e.isSpecialKey() || !cc)){
4384 if(!this.maskRe.test(cc)){
4389 * Clear any invalid styles/messages for this field
4391 clearInvalid : function(){
4393 if(!this.el || this.preventMark){ // not rendered
4396 this.el.removeClass(this.invalidClass);
4398 switch(this.msgTarget){
4400 this.el.dom.qtip = '';
4403 this.el.dom.title = '';
4407 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
4412 this.errorIcon.dom.qtip = '';
4413 this.errorIcon.hide();
4414 this.un('resize', this.alignErrorIcon, this);
4418 var t = Roo.getDom(this.msgTarget);
4420 t.style.display = 'none';
4424 this.fireEvent('valid', this);
4427 * Mark this field as invalid
4428 * @param {String} msg The validation message
4430 markInvalid : function(msg){
4431 if(!this.el || this.preventMark){ // not rendered
4434 this.el.addClass(this.invalidClass);
4436 msg = msg || this.invalidText;
4437 switch(this.msgTarget){
4439 this.el.dom.qtip = msg;
4440 this.el.dom.qclass = 'x-form-invalid-tip';
4441 if(Roo.QuickTips){ // fix for floating editors interacting with DND
4442 Roo.QuickTips.enable();
4446 this.el.dom.title = msg;
4450 var elp = this.el.findParent('.x-form-element', 5, true);
4451 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
4452 this.errorEl.setWidth(elp.getWidth(true)-20);
4454 this.errorEl.update(msg);
4455 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
4458 if(!this.errorIcon){
4459 var elp = this.el.findParent('.x-form-element', 5, true);
4460 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
4462 this.alignErrorIcon();
4463 this.errorIcon.dom.qtip = msg;
4464 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
4465 this.errorIcon.show();
4466 this.on('resize', this.alignErrorIcon, this);
4469 var t = Roo.getDom(this.msgTarget);
4471 t.style.display = this.msgDisplay;
4475 this.fireEvent('invalid', this, msg);
4478 SafariOnKeyDown : function(event)
4480 // this is a workaround for a password hang bug on chrome/ webkit.
4482 var isSelectAll = false;
4484 if(this.inputEl().dom.selectionEnd > 0){
4485 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
4487 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
4488 event.preventDefault();
4493 if(isSelectAll){ // backspace and delete key
4495 event.preventDefault();
4496 // this is very hacky as keydown always get's upper case.
4498 var cc = String.fromCharCode(event.getCharCode());
4499 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
4515 * @class Roo.bootstrap.TextArea
4516 * @extends Roo.bootstrap.Input
4517 * Bootstrap TextArea class
4518 * @cfg {Number} cols Specifies the visible width of a text area
4519 * @cfg {Number} rows Specifies the visible number of lines in a text area
4520 * @cfg {Number} readOnly Specifies that a text area should be read-only
4521 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
4522 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
4523 * @cfg {string} html text
4526 * Create a new TextArea
4527 * @param {Object} config The config object
4530 Roo.bootstrap.TextArea = function(config){
4531 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
4535 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
4545 getAutoCreate : function(){
4547 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4558 value : this.value || '',
4559 html: this.html || '',
4560 cls : 'form-control',
4561 placeholder : this.placeholder || ''
4565 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4566 input.maxLength = this.maxLength;
4570 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
4574 input.cols = this.cols;
4577 if (this.readOnly) {
4578 input.readonly = true;
4582 input.name = this.name;
4586 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
4590 ['xs','sm','md','lg'].map(function(size){
4591 if (settings[size]) {
4592 cfg.cls += ' col-' + size + '-' + settings[size];
4596 var inputblock = input;
4598 if (this.before || this.after) {
4601 cls : 'input-group',
4605 inputblock.cn.push({
4607 cls : 'input-group-addon',
4611 inputblock.cn.push(input);
4613 inputblock.cn.push({
4615 cls : 'input-group-addon',
4622 if (align ==='left' && this.fieldLabel.length) {
4623 Roo.log("left and has label");
4629 cls : 'control-label col-sm-' + this.labelWidth,
4630 html : this.fieldLabel
4634 cls : "col-sm-" + (12 - this.labelWidth),
4641 } else if ( this.fieldLabel.length) {
4647 //cls : 'input-group-addon',
4648 html : this.fieldLabel
4658 Roo.log(" no label && no align");
4668 if (this.disabled) {
4669 input.disabled=true;
4676 * return the real textarea element.
4678 inputEl: function ()
4680 return this.el.select('textarea.form-control',true).first();
4688 * trigger field - base class for combo..
4693 * @class Roo.bootstrap.TriggerField
4694 * @extends Roo.bootstrap.Input
4695 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
4696 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
4697 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
4698 * for which you can provide a custom implementation. For example:
4700 var trigger = new Roo.bootstrap.TriggerField();
4701 trigger.onTriggerClick = myTriggerFn;
4702 trigger.applyTo('my-field');
4705 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
4706 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
4707 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
4708 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
4710 * Create a new TriggerField.
4711 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
4712 * to the base TextField)
4714 Roo.bootstrap.TriggerField = function(config){
4715 this.mimicing = false;
4716 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
4719 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
4721 * @cfg {String} triggerClass A CSS class to apply to the trigger
4724 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
4728 /** @cfg {Boolean} grow @hide */
4729 /** @cfg {Number} growMin @hide */
4730 /** @cfg {Number} growMax @hide */
4736 autoSize: Roo.emptyFn,
4743 actionMode : 'wrap',
4747 getAutoCreate : function(){
4749 var parent = this.parent();
4751 var align = this.parentLabelAlign();
4756 cls: 'form-group' //input-group
4763 type : this.inputType,
4764 cls : 'form-control',
4765 autocomplete: 'off',
4766 placeholder : this.placeholder || ''
4770 input.name = this.name;
4773 input.cls += ' input-' + this.size;
4776 cls: 'combobox-container input-group',
4781 cls: 'form-hidden-field'
4786 cls : 'typeahead typeahead-long dropdown-menu',
4787 style : 'display:none'
4791 cls : 'input-group-addon btn dropdown-toggle',
4799 cls: 'combobox-clear',
4816 if (align ==='left' && this.fieldLabel.length) {
4820 Roo.log("left and has label");
4826 cls : 'col-sm-2 control-label',
4827 html : this.fieldLabel
4838 } else if ( this.fieldLabel.length) {
4844 //cls : 'input-group-addon',
4845 html : this.fieldLabel
4855 Roo.log(" no label && no align");
4862 ['xs','sm','md','lg'].map(function(size){
4863 if (settings[size]) {
4864 cfg.cls += ' col-' + size + '-' + settings[size];
4870 if (this.disabled) {
4871 input.disabled=true;
4880 onResize : function(w, h){
4881 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
4882 // if(typeof w == 'number'){
4883 // var x = w - this.trigger.getWidth();
4884 // this.inputEl().setWidth(this.adjustWidth('input', x));
4885 // this.trigger.setStyle('left', x+'px');
4890 adjustSize : Roo.BoxComponent.prototype.adjustSize,
4893 getResizeEl : function(){
4894 return this.inputEl();
4898 getPositionEl : function(){
4899 return this.inputEl();
4903 alignErrorIcon : function(){
4904 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
4908 initEvents : function(){
4910 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
4911 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
4913 this.trigger = this.el.select('span.dropdown-toggle',true).first();
4914 if(this.hideTrigger){
4915 this.trigger.setDisplayed(false);
4917 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
4918 //this.trigger.addClassOnOver('x-form-trigger-over');
4919 //this.trigger.addClassOnClick('x-form-trigger-click');
4922 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
4927 initTrigger : function(){
4932 onDestroy : function(){
4934 this.trigger.removeAllListeners();
4935 // this.trigger.remove();
4938 // this.wrap.remove();
4940 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
4944 onFocus : function(){
4945 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
4948 this.wrap.addClass('x-trigger-wrap-focus');
4949 this.mimicing = true;
4950 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
4951 if(this.monitorTab){
4952 this.el.on("keydown", this.checkTab, this);
4959 checkTab : function(e){
4960 if(e.getKey() == e.TAB){
4966 onBlur : function(){
4971 mimicBlur : function(e, t){
4973 if(!this.wrap.contains(t) && this.validateBlur()){
4980 triggerBlur : function(){
4981 this.mimicing = false;
4982 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
4983 if(this.monitorTab){
4984 this.el.un("keydown", this.checkTab, this);
4986 //this.wrap.removeClass('x-trigger-wrap-focus');
4987 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
4991 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
4992 validateBlur : function(e, t){
4997 onDisable : function(){
4998 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
5000 // this.wrap.addClass('x-item-disabled');
5005 onEnable : function(){
5006 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
5008 // this.el.removeClass('x-item-disabled');
5013 onShow : function(){
5014 var ae = this.getActionEl();
5017 ae.dom.style.display = '';
5018 ae.dom.style.visibility = 'visible';
5024 onHide : function(){
5025 var ae = this.getActionEl();
5026 ae.dom.style.display = 'none';
5030 * The function that should handle the trigger's click event. This method does nothing by default until overridden
5031 * by an implementing function.
5033 * @param {EventObject} e
5035 onTriggerClick : Roo.emptyFn
5039 * Ext JS Library 1.1.1
5040 * Copyright(c) 2006-2007, Ext JS, LLC.
5042 * Originally Released Under LGPL - original licence link has changed is not relivant.
5045 * <script type="text/javascript">
5050 * @class Roo.data.SortTypes
5052 * Defines the default sorting (casting?) comparison functions used when sorting data.
5054 Roo.data.SortTypes = {
5056 * Default sort that does nothing
5057 * @param {Mixed} s The value being converted
5058 * @return {Mixed} The comparison value
5065 * The regular expression used to strip tags
5069 stripTagsRE : /<\/?[^>]+>/gi,
5072 * Strips all HTML tags to sort on text only
5073 * @param {Mixed} s The value being converted
5074 * @return {String} The comparison value
5076 asText : function(s){
5077 return String(s).replace(this.stripTagsRE, "");
5081 * Strips all HTML tags to sort on text only - Case insensitive
5082 * @param {Mixed} s The value being converted
5083 * @return {String} The comparison value
5085 asUCText : function(s){
5086 return String(s).toUpperCase().replace(this.stripTagsRE, "");
5090 * Case insensitive string
5091 * @param {Mixed} s The value being converted
5092 * @return {String} The comparison value
5094 asUCString : function(s) {
5095 return String(s).toUpperCase();
5100 * @param {Mixed} s The value being converted
5101 * @return {Number} The comparison value
5103 asDate : function(s) {
5107 if(s instanceof Date){
5110 return Date.parse(String(s));
5115 * @param {Mixed} s The value being converted
5116 * @return {Float} The comparison value
5118 asFloat : function(s) {
5119 var val = parseFloat(String(s).replace(/,/g, ""));
5120 if(isNaN(val)) val = 0;
5126 * @param {Mixed} s The value being converted
5127 * @return {Number} The comparison value
5129 asInt : function(s) {
5130 var val = parseInt(String(s).replace(/,/g, ""));
5131 if(isNaN(val)) val = 0;
5136 * Ext JS Library 1.1.1
5137 * Copyright(c) 2006-2007, Ext JS, LLC.
5139 * Originally Released Under LGPL - original licence link has changed is not relivant.
5142 * <script type="text/javascript">
5146 * @class Roo.data.Record
5147 * Instances of this class encapsulate both record <em>definition</em> information, and record
5148 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
5149 * to access Records cached in an {@link Roo.data.Store} object.<br>
5151 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
5152 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
5155 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
5157 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
5158 * {@link #create}. The parameters are the same.
5159 * @param {Array} data An associative Array of data values keyed by the field name.
5160 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
5161 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
5162 * not specified an integer id is generated.
5164 Roo.data.Record = function(data, id){
5165 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
5170 * Generate a constructor for a specific record layout.
5171 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
5172 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
5173 * Each field definition object may contain the following properties: <ul>
5174 * <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,
5175 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
5176 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
5177 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
5178 * is being used, then this is a string containing the javascript expression to reference the data relative to
5179 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
5180 * to the data item relative to the record element. If the mapping expression is the same as the field name,
5181 * this may be omitted.</p></li>
5182 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
5183 * <ul><li>auto (Default, implies no conversion)</li>
5188 * <li>date</li></ul></p></li>
5189 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
5190 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
5191 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
5192 * by the Reader into an object that will be stored in the Record. It is passed the
5193 * following parameters:<ul>
5194 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
5196 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
5198 * <br>usage:<br><pre><code>
5199 var TopicRecord = Roo.data.Record.create(
5200 {name: 'title', mapping: 'topic_title'},
5201 {name: 'author', mapping: 'username'},
5202 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
5203 {name: 'lastPost', mapping: 'post_time', type: 'date'},
5204 {name: 'lastPoster', mapping: 'user2'},
5205 {name: 'excerpt', mapping: 'post_text'}
5208 var myNewRecord = new TopicRecord({
5209 title: 'Do my job please',
5212 lastPost: new Date(),
5213 lastPoster: 'Animal',
5214 excerpt: 'No way dude!'
5216 myStore.add(myNewRecord);
5221 Roo.data.Record.create = function(o){
5223 f.superclass.constructor.apply(this, arguments);
5225 Roo.extend(f, Roo.data.Record);
5226 var p = f.prototype;
5227 p.fields = new Roo.util.MixedCollection(false, function(field){
5230 for(var i = 0, len = o.length; i < len; i++){
5231 p.fields.add(new Roo.data.Field(o[i]));
5233 f.getField = function(name){
5234 return p.fields.get(name);
5239 Roo.data.Record.AUTO_ID = 1000;
5240 Roo.data.Record.EDIT = 'edit';
5241 Roo.data.Record.REJECT = 'reject';
5242 Roo.data.Record.COMMIT = 'commit';
5244 Roo.data.Record.prototype = {
5246 * Readonly flag - true if this record has been modified.
5255 join : function(store){
5260 * Set the named field to the specified value.
5261 * @param {String} name The name of the field to set.
5262 * @param {Object} value The value to set the field to.
5264 set : function(name, value){
5265 if(this.data[name] == value){
5272 if(typeof this.modified[name] == 'undefined'){
5273 this.modified[name] = this.data[name];
5275 this.data[name] = value;
5276 if(!this.editing && this.store){
5277 this.store.afterEdit(this);
5282 * Get the value of the named field.
5283 * @param {String} name The name of the field to get the value of.
5284 * @return {Object} The value of the field.
5286 get : function(name){
5287 return this.data[name];
5291 beginEdit : function(){
5292 this.editing = true;
5297 cancelEdit : function(){
5298 this.editing = false;
5299 delete this.modified;
5303 endEdit : function(){
5304 this.editing = false;
5305 if(this.dirty && this.store){
5306 this.store.afterEdit(this);
5311 * Usually called by the {@link Roo.data.Store} which owns the Record.
5312 * Rejects all changes made to the Record since either creation, or the last commit operation.
5313 * Modified fields are reverted to their original values.
5315 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5316 * of reject operations.
5318 reject : function(){
5319 var m = this.modified;
5321 if(typeof m[n] != "function"){
5322 this.data[n] = m[n];
5326 delete this.modified;
5327 this.editing = false;
5329 this.store.afterReject(this);
5334 * Usually called by the {@link Roo.data.Store} which owns the Record.
5335 * Commits all changes made to the Record since either creation, or the last commit operation.
5337 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5338 * of commit operations.
5340 commit : function(){
5342 delete this.modified;
5343 this.editing = false;
5345 this.store.afterCommit(this);
5350 hasError : function(){
5351 return this.error != null;
5355 clearError : function(){
5360 * Creates a copy of this record.
5361 * @param {String} id (optional) A new record id if you don't want to use this record's id
5364 copy : function(newId) {
5365 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
5369 * Ext JS Library 1.1.1
5370 * Copyright(c) 2006-2007, Ext JS, LLC.
5372 * Originally Released Under LGPL - original licence link has changed is not relivant.
5375 * <script type="text/javascript">
5381 * @class Roo.data.Store
5382 * @extends Roo.util.Observable
5383 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
5384 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
5386 * 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
5387 * has no knowledge of the format of the data returned by the Proxy.<br>
5389 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
5390 * instances from the data object. These records are cached and made available through accessor functions.
5392 * Creates a new Store.
5393 * @param {Object} config A config object containing the objects needed for the Store to access data,
5394 * and read the data into Records.
5396 Roo.data.Store = function(config){
5397 this.data = new Roo.util.MixedCollection(false);
5398 this.data.getKey = function(o){
5401 this.baseParams = {};
5408 "multisort" : "_multisort"
5411 if(config && config.data){
5412 this.inlineData = config.data;
5416 Roo.apply(this, config);
5418 if(this.reader){ // reader passed
5419 this.reader = Roo.factory(this.reader, Roo.data);
5420 this.reader.xmodule = this.xmodule || false;
5421 if(!this.recordType){
5422 this.recordType = this.reader.recordType;
5424 if(this.reader.onMetaChange){
5425 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
5429 if(this.recordType){
5430 this.fields = this.recordType.prototype.fields;
5436 * @event datachanged
5437 * Fires when the data cache has changed, and a widget which is using this Store
5438 * as a Record cache should refresh its view.
5439 * @param {Store} this
5444 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
5445 * @param {Store} this
5446 * @param {Object} meta The JSON metadata
5451 * Fires when Records have been added to the Store
5452 * @param {Store} this
5453 * @param {Roo.data.Record[]} records The array of Records added
5454 * @param {Number} index The index at which the record(s) were added
5459 * Fires when a Record has been removed from the Store
5460 * @param {Store} this
5461 * @param {Roo.data.Record} record The Record that was removed
5462 * @param {Number} index The index at which the record was removed
5467 * Fires when a Record has been updated
5468 * @param {Store} this
5469 * @param {Roo.data.Record} record The Record that was updated
5470 * @param {String} operation The update operation being performed. Value may be one of:
5472 Roo.data.Record.EDIT
5473 Roo.data.Record.REJECT
5474 Roo.data.Record.COMMIT
5480 * Fires when the data cache has been cleared.
5481 * @param {Store} this
5486 * Fires before a request is made for a new data object. If the beforeload handler returns false
5487 * the load action will be canceled.
5488 * @param {Store} this
5489 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5493 * @event beforeloadadd
5494 * Fires after a new set of Records has been loaded.
5495 * @param {Store} this
5496 * @param {Roo.data.Record[]} records The Records that were loaded
5497 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5499 beforeloadadd : true,
5502 * Fires after a new set of Records has been loaded, before they are added to the store.
5503 * @param {Store} this
5504 * @param {Roo.data.Record[]} records The Records that were loaded
5505 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5506 * @params {Object} return from reader
5510 * @event loadexception
5511 * Fires if an exception occurs in the Proxy during loading.
5512 * Called with the signature of the Proxy's "loadexception" event.
5513 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
5516 * @param {Object} return from JsonData.reader() - success, totalRecords, records
5517 * @param {Object} load options
5518 * @param {Object} jsonData from your request (normally this contains the Exception)
5520 loadexception : true
5524 this.proxy = Roo.factory(this.proxy, Roo.data);
5525 this.proxy.xmodule = this.xmodule || false;
5526 this.relayEvents(this.proxy, ["loadexception"]);
5528 this.sortToggle = {};
5529 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
5531 Roo.data.Store.superclass.constructor.call(this);
5533 if(this.inlineData){
5534 this.loadData(this.inlineData);
5535 delete this.inlineData;
5539 Roo.extend(Roo.data.Store, Roo.util.Observable, {
5541 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
5542 * without a remote query - used by combo/forms at present.
5546 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
5549 * @cfg {Array} data Inline data to be loaded when the store is initialized.
5552 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
5553 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
5556 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
5557 * on any HTTP request
5560 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
5563 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
5567 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
5568 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
5573 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
5574 * loaded or when a record is removed. (defaults to false).
5576 pruneModifiedRecords : false,
5582 * Add Records to the Store and fires the add event.
5583 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
5585 add : function(records){
5586 records = [].concat(records);
5587 for(var i = 0, len = records.length; i < len; i++){
5588 records[i].join(this);
5590 var index = this.data.length;
5591 this.data.addAll(records);
5592 this.fireEvent("add", this, records, index);
5596 * Remove a Record from the Store and fires the remove event.
5597 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
5599 remove : function(record){
5600 var index = this.data.indexOf(record);
5601 this.data.removeAt(index);
5602 if(this.pruneModifiedRecords){
5603 this.modified.remove(record);
5605 this.fireEvent("remove", this, record, index);
5609 * Remove all Records from the Store and fires the clear event.
5611 removeAll : function(){
5613 if(this.pruneModifiedRecords){
5616 this.fireEvent("clear", this);
5620 * Inserts Records to the Store at the given index and fires the add event.
5621 * @param {Number} index The start index at which to insert the passed Records.
5622 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
5624 insert : function(index, records){
5625 records = [].concat(records);
5626 for(var i = 0, len = records.length; i < len; i++){
5627 this.data.insert(index, records[i]);
5628 records[i].join(this);
5630 this.fireEvent("add", this, records, index);
5634 * Get the index within the cache of the passed Record.
5635 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
5636 * @return {Number} The index of the passed Record. Returns -1 if not found.
5638 indexOf : function(record){
5639 return this.data.indexOf(record);
5643 * Get the index within the cache of the Record with the passed id.
5644 * @param {String} id The id of the Record to find.
5645 * @return {Number} The index of the Record. Returns -1 if not found.
5647 indexOfId : function(id){
5648 return this.data.indexOfKey(id);
5652 * Get the Record with the specified id.
5653 * @param {String} id The id of the Record to find.
5654 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
5656 getById : function(id){
5657 return this.data.key(id);
5661 * Get the Record at the specified index.
5662 * @param {Number} index The index of the Record to find.
5663 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
5665 getAt : function(index){
5666 return this.data.itemAt(index);
5670 * Returns a range of Records between specified indices.
5671 * @param {Number} startIndex (optional) The starting index (defaults to 0)
5672 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
5673 * @return {Roo.data.Record[]} An array of Records
5675 getRange : function(start, end){
5676 return this.data.getRange(start, end);
5680 storeOptions : function(o){
5681 o = Roo.apply({}, o);
5684 this.lastOptions = o;
5688 * Loads the Record cache from the configured Proxy using the configured Reader.
5690 * If using remote paging, then the first load call must specify the <em>start</em>
5691 * and <em>limit</em> properties in the options.params property to establish the initial
5692 * position within the dataset, and the number of Records to cache on each read from the Proxy.
5694 * <strong>It is important to note that for remote data sources, loading is asynchronous,
5695 * and this call will return before the new data has been loaded. Perform any post-processing
5696 * in a callback function, or in a "load" event handler.</strong>
5698 * @param {Object} options An object containing properties which control loading options:<ul>
5699 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
5700 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
5701 * passed the following arguments:<ul>
5702 * <li>r : Roo.data.Record[]</li>
5703 * <li>options: Options object from the load call</li>
5704 * <li>success: Boolean success indicator</li></ul></li>
5705 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
5706 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
5709 load : function(options){
5710 options = options || {};
5711 if(this.fireEvent("beforeload", this, options) !== false){
5712 this.storeOptions(options);
5713 var p = Roo.apply(options.params || {}, this.baseParams);
5714 // if meta was not loaded from remote source.. try requesting it.
5715 if (!this.reader.metaFromRemote) {
5718 if(this.sortInfo && this.remoteSort){
5719 var pn = this.paramNames;
5720 p[pn["sort"]] = this.sortInfo.field;
5721 p[pn["dir"]] = this.sortInfo.direction;
5723 if (this.multiSort) {
5724 var pn = this.paramNames;
5725 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
5728 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5733 * Reloads the Record cache from the configured Proxy using the configured Reader and
5734 * the options from the last load operation performed.
5735 * @param {Object} options (optional) An object containing properties which may override the options
5736 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5737 * the most recently used options are reused).
5739 reload : function(options){
5740 this.load(Roo.applyIf(options||{}, this.lastOptions));
5744 // Called as a callback by the Reader during a load operation.
5745 loadRecords : function(o, options, success){
5746 if(!o || success === false){
5747 if(success !== false){
5748 this.fireEvent("load", this, [], options, o);
5750 if(options.callback){
5751 options.callback.call(options.scope || this, [], options, false);
5755 // if data returned failure - throw an exception.
5756 if (o.success === false) {
5757 // show a message if no listener is registered.
5758 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
5759 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
5761 // loadmask wil be hooked into this..
5762 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
5765 var r = o.records, t = o.totalRecords || r.length;
5767 this.fireEvent("beforeloadadd", this, r, options, o);
5769 if(!options || options.add !== true){
5770 if(this.pruneModifiedRecords){
5773 for(var i = 0, len = r.length; i < len; i++){
5777 this.data = this.snapshot;
5778 delete this.snapshot;
5781 this.data.addAll(r);
5782 this.totalLength = t;
5784 this.fireEvent("datachanged", this);
5786 this.totalLength = Math.max(t, this.data.length+r.length);
5789 this.fireEvent("load", this, r, options, o);
5790 if(options.callback){
5791 options.callback.call(options.scope || this, r, options, true);
5797 * Loads data from a passed data block. A Reader which understands the format of the data
5798 * must have been configured in the constructor.
5799 * @param {Object} data The data block from which to read the Records. The format of the data expected
5800 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5801 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5803 loadData : function(o, append){
5804 var r = this.reader.readRecords(o);
5805 this.loadRecords(r, {add: append}, true);
5809 * Gets the number of cached records.
5811 * <em>If using paging, this may not be the total size of the dataset. If the data object
5812 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5813 * the data set size</em>
5815 getCount : function(){
5816 return this.data.length || 0;
5820 * Gets the total number of records in the dataset as returned by the server.
5822 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5823 * the dataset size</em>
5825 getTotalCount : function(){
5826 return this.totalLength || 0;
5830 * Returns the sort state of the Store as an object with two properties:
5832 field {String} The name of the field by which the Records are sorted
5833 direction {String} The sort order, "ASC" or "DESC"
5836 getSortState : function(){
5837 return this.sortInfo;
5841 applySort : function(){
5842 if(this.sortInfo && !this.remoteSort){
5843 var s = this.sortInfo, f = s.field;
5844 var st = this.fields.get(f).sortType;
5845 var fn = function(r1, r2){
5846 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5847 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5849 this.data.sort(s.direction, fn);
5850 if(this.snapshot && this.snapshot != this.data){
5851 this.snapshot.sort(s.direction, fn);
5857 * Sets the default sort column and order to be used by the next load operation.
5858 * @param {String} fieldName The name of the field to sort by.
5859 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5861 setDefaultSort : function(field, dir){
5862 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5867 * If remote sorting is used, the sort is performed on the server, and the cache is
5868 * reloaded. If local sorting is used, the cache is sorted internally.
5869 * @param {String} fieldName The name of the field to sort by.
5870 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5872 sort : function(fieldName, dir){
5873 var f = this.fields.get(fieldName);
5875 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
5877 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
5878 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5883 this.sortToggle[f.name] = dir;
5884 this.sortInfo = {field: f.name, direction: dir};
5885 if(!this.remoteSort){
5887 this.fireEvent("datachanged", this);
5889 this.load(this.lastOptions);
5894 * Calls the specified function for each of the Records in the cache.
5895 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5896 * Returning <em>false</em> aborts and exits the iteration.
5897 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5899 each : function(fn, scope){
5900 this.data.each(fn, scope);
5904 * Gets all records modified since the last commit. Modified records are persisted across load operations
5905 * (e.g., during paging).
5906 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5908 getModifiedRecords : function(){
5909 return this.modified;
5913 createFilterFn : function(property, value, anyMatch){
5914 if(!value.exec){ // not a regex
5915 value = String(value);
5916 if(value.length == 0){
5919 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5922 return value.test(r.data[property]);
5927 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5928 * @param {String} property A field on your records
5929 * @param {Number} start The record index to start at (defaults to 0)
5930 * @param {Number} end The last record index to include (defaults to length - 1)
5931 * @return {Number} The sum
5933 sum : function(property, start, end){
5934 var rs = this.data.items, v = 0;
5936 end = (end || end === 0) ? end : rs.length-1;
5938 for(var i = start; i <= end; i++){
5939 v += (rs[i].data[property] || 0);
5945 * Filter the records by a specified property.
5946 * @param {String} field A field on your records
5947 * @param {String/RegExp} value Either a string that the field
5948 * should start with or a RegExp to test against the field
5949 * @param {Boolean} anyMatch True to match any part not just the beginning
5951 filter : function(property, value, anyMatch){
5952 var fn = this.createFilterFn(property, value, anyMatch);
5953 return fn ? this.filterBy(fn) : this.clearFilter();
5957 * Filter by a function. The specified function will be called with each
5958 * record in this data source. If the function returns true the record is included,
5959 * otherwise it is filtered.
5960 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5961 * @param {Object} scope (optional) The scope of the function (defaults to this)
5963 filterBy : function(fn, scope){
5964 this.snapshot = this.snapshot || this.data;
5965 this.data = this.queryBy(fn, scope||this);
5966 this.fireEvent("datachanged", this);
5970 * Query the records by a specified property.
5971 * @param {String} field A field on your records
5972 * @param {String/RegExp} value Either a string that the field
5973 * should start with or a RegExp to test against the field
5974 * @param {Boolean} anyMatch True to match any part not just the beginning
5975 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5977 query : function(property, value, anyMatch){
5978 var fn = this.createFilterFn(property, value, anyMatch);
5979 return fn ? this.queryBy(fn) : this.data.clone();
5983 * Query by a function. The specified function will be called with each
5984 * record in this data source. If the function returns true the record is included
5986 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5987 * @param {Object} scope (optional) The scope of the function (defaults to this)
5988 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5990 queryBy : function(fn, scope){
5991 var data = this.snapshot || this.data;
5992 return data.filterBy(fn, scope||this);
5996 * Collects unique values for a particular dataIndex from this store.
5997 * @param {String} dataIndex The property to collect
5998 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5999 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
6000 * @return {Array} An array of the unique values
6002 collect : function(dataIndex, allowNull, bypassFilter){
6003 var d = (bypassFilter === true && this.snapshot) ?
6004 this.snapshot.items : this.data.items;
6005 var v, sv, r = [], l = {};
6006 for(var i = 0, len = d.length; i < len; i++){
6007 v = d[i].data[dataIndex];
6009 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
6018 * Revert to a view of the Record cache with no filtering applied.
6019 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
6021 clearFilter : function(suppressEvent){
6022 if(this.snapshot && this.snapshot != this.data){
6023 this.data = this.snapshot;
6024 delete this.snapshot;
6025 if(suppressEvent !== true){
6026 this.fireEvent("datachanged", this);
6032 afterEdit : function(record){
6033 if(this.modified.indexOf(record) == -1){
6034 this.modified.push(record);
6036 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
6040 afterReject : function(record){
6041 this.modified.remove(record);
6042 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
6046 afterCommit : function(record){
6047 this.modified.remove(record);
6048 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
6052 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
6053 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
6055 commitChanges : function(){
6056 var m = this.modified.slice(0);
6058 for(var i = 0, len = m.length; i < len; i++){
6064 * Cancel outstanding changes on all changed records.
6066 rejectChanges : function(){
6067 var m = this.modified.slice(0);
6069 for(var i = 0, len = m.length; i < len; i++){
6074 onMetaChange : function(meta, rtype, o){
6075 this.recordType = rtype;
6076 this.fields = rtype.prototype.fields;
6077 delete this.snapshot;
6078 this.sortInfo = meta.sortInfo || this.sortInfo;
6080 this.fireEvent('metachange', this, this.reader.meta);
6084 * Ext JS Library 1.1.1
6085 * Copyright(c) 2006-2007, Ext JS, LLC.
6087 * Originally Released Under LGPL - original licence link has changed is not relivant.
6090 * <script type="text/javascript">
6094 * @class Roo.data.SimpleStore
6095 * @extends Roo.data.Store
6096 * Small helper class to make creating Stores from Array data easier.
6097 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
6098 * @cfg {Array} fields An array of field definition objects, or field name strings.
6099 * @cfg {Array} data The multi-dimensional array of data
6101 * @param {Object} config
6103 Roo.data.SimpleStore = function(config){
6104 Roo.data.SimpleStore.superclass.constructor.call(this, {
6106 reader: new Roo.data.ArrayReader({
6109 Roo.data.Record.create(config.fields)
6111 proxy : new Roo.data.MemoryProxy(config.data)
6115 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
6117 * Ext JS Library 1.1.1
6118 * Copyright(c) 2006-2007, Ext JS, LLC.
6120 * Originally Released Under LGPL - original licence link has changed is not relivant.
6123 * <script type="text/javascript">
6128 * @extends Roo.data.Store
6129 * @class Roo.data.JsonStore
6130 * Small helper class to make creating Stores for JSON data easier. <br/>
6132 var store = new Roo.data.JsonStore({
6133 url: 'get-images.php',
6135 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
6138 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
6139 * JsonReader and HttpProxy (unless inline data is provided).</b>
6140 * @cfg {Array} fields An array of field definition objects, or field name strings.
6142 * @param {Object} config
6144 Roo.data.JsonStore = function(c){
6145 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
6146 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
6147 reader: new Roo.data.JsonReader(c, c.fields)
6150 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
6152 * Ext JS Library 1.1.1
6153 * Copyright(c) 2006-2007, Ext JS, LLC.
6155 * Originally Released Under LGPL - original licence link has changed is not relivant.
6158 * <script type="text/javascript">
6162 Roo.data.Field = function(config){
6163 if(typeof config == "string"){
6164 config = {name: config};
6166 Roo.apply(this, config);
6172 var st = Roo.data.SortTypes;
6173 // named sortTypes are supported, here we look them up
6174 if(typeof this.sortType == "string"){
6175 this.sortType = st[this.sortType];
6178 // set default sortType for strings and dates
6182 this.sortType = st.asUCString;
6185 this.sortType = st.asDate;
6188 this.sortType = st.none;
6193 var stripRe = /[\$,%]/g;
6195 // prebuilt conversion function for this field, instead of
6196 // switching every time we're reading a value
6198 var cv, dateFormat = this.dateFormat;
6203 cv = function(v){ return v; };
6206 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
6210 return v !== undefined && v !== null && v !== '' ?
6211 parseInt(String(v).replace(stripRe, ""), 10) : '';
6216 return v !== undefined && v !== null && v !== '' ?
6217 parseFloat(String(v).replace(stripRe, ""), 10) : '';
6222 cv = function(v){ return v === true || v === "true" || v == 1; };
6229 if(v instanceof Date){
6233 if(dateFormat == "timestamp"){
6234 return new Date(v*1000);
6236 return Date.parseDate(v, dateFormat);
6238 var parsed = Date.parse(v);
6239 return parsed ? new Date(parsed) : null;
6248 Roo.data.Field.prototype = {
6256 * Ext JS Library 1.1.1
6257 * Copyright(c) 2006-2007, Ext JS, LLC.
6259 * Originally Released Under LGPL - original licence link has changed is not relivant.
6262 * <script type="text/javascript">
6265 // Base class for reading structured data from a data source. This class is intended to be
6266 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
6269 * @class Roo.data.DataReader
6270 * Base class for reading structured data from a data source. This class is intended to be
6271 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
6274 Roo.data.DataReader = function(meta, recordType){
6278 this.recordType = recordType instanceof Array ?
6279 Roo.data.Record.create(recordType) : recordType;
6282 Roo.data.DataReader.prototype = {
6284 * Create an empty record
6285 * @param {Object} data (optional) - overlay some values
6286 * @return {Roo.data.Record} record created.
6288 newRow : function(d) {
6290 this.recordType.prototype.fields.each(function(c) {
6292 case 'int' : da[c.name] = 0; break;
6293 case 'date' : da[c.name] = new Date(); break;
6294 case 'float' : da[c.name] = 0.0; break;
6295 case 'boolean' : da[c.name] = false; break;
6296 default : da[c.name] = ""; break;
6300 return new this.recordType(Roo.apply(da, d));
6305 * Ext JS Library 1.1.1
6306 * Copyright(c) 2006-2007, Ext JS, LLC.
6308 * Originally Released Under LGPL - original licence link has changed is not relivant.
6311 * <script type="text/javascript">
6315 * @class Roo.data.DataProxy
6316 * @extends Roo.data.Observable
6317 * This class is an abstract base class for implementations which provide retrieval of
6318 * unformatted data objects.<br>
6320 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
6321 * (of the appropriate type which knows how to parse the data object) to provide a block of
6322 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
6324 * Custom implementations must implement the load method as described in
6325 * {@link Roo.data.HttpProxy#load}.
6327 Roo.data.DataProxy = function(){
6331 * Fires before a network request is made to retrieve a data object.
6332 * @param {Object} This DataProxy object.
6333 * @param {Object} params The params parameter to the load function.
6338 * Fires before the load method's callback is called.
6339 * @param {Object} This DataProxy object.
6340 * @param {Object} o The data object.
6341 * @param {Object} arg The callback argument object passed to the load function.
6345 * @event loadexception
6346 * Fires if an Exception occurs during data retrieval.
6347 * @param {Object} This DataProxy object.
6348 * @param {Object} o The data object.
6349 * @param {Object} arg The callback argument object passed to the load function.
6350 * @param {Object} e The Exception.
6352 loadexception : true
6354 Roo.data.DataProxy.superclass.constructor.call(this);
6357 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
6360 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
6364 * Ext JS Library 1.1.1
6365 * Copyright(c) 2006-2007, Ext JS, LLC.
6367 * Originally Released Under LGPL - original licence link has changed is not relivant.
6370 * <script type="text/javascript">
6373 * @class Roo.data.MemoryProxy
6374 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
6375 * to the Reader when its load method is called.
6377 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
6379 Roo.data.MemoryProxy = function(data){
6383 Roo.data.MemoryProxy.superclass.constructor.call(this);
6387 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
6389 * Load data from the requested source (in this case an in-memory
6390 * data object passed to the constructor), read the data object into
6391 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6392 * process that block using the passed callback.
6393 * @param {Object} params This parameter is not used by the MemoryProxy class.
6394 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6395 * object into a block of Roo.data.Records.
6396 * @param {Function} callback The function into which to pass the block of Roo.data.records.
6397 * The function must be passed <ul>
6398 * <li>The Record block object</li>
6399 * <li>The "arg" argument from the load function</li>
6400 * <li>A boolean success indicator</li>
6402 * @param {Object} scope The scope in which to call the callback
6403 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6405 load : function(params, reader, callback, scope, arg){
6406 params = params || {};
6409 result = reader.readRecords(this.data);
6411 this.fireEvent("loadexception", this, arg, null, e);
6412 callback.call(scope, null, arg, false);
6415 callback.call(scope, result, arg, true);
6419 update : function(params, records){
6424 * Ext JS Library 1.1.1
6425 * Copyright(c) 2006-2007, Ext JS, LLC.
6427 * Originally Released Under LGPL - original licence link has changed is not relivant.
6430 * <script type="text/javascript">
6433 * @class Roo.data.HttpProxy
6434 * @extends Roo.data.DataProxy
6435 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
6436 * configured to reference a certain URL.<br><br>
6438 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
6439 * from which the running page was served.<br><br>
6441 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
6443 * Be aware that to enable the browser to parse an XML document, the server must set
6444 * the Content-Type header in the HTTP response to "text/xml".
6446 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
6447 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
6448 * will be used to make the request.
6450 Roo.data.HttpProxy = function(conn){
6451 Roo.data.HttpProxy.superclass.constructor.call(this);
6452 // is conn a conn config or a real conn?
6454 this.useAjax = !conn || !conn.events;
6458 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
6459 // thse are take from connection...
6462 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
6465 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
6466 * extra parameters to each request made by this object. (defaults to undefined)
6469 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
6470 * to each request made by this object. (defaults to undefined)
6473 * @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)
6476 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
6479 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
6485 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
6489 * Return the {@link Roo.data.Connection} object being used by this Proxy.
6490 * @return {Connection} The Connection object. This object may be used to subscribe to events on
6491 * a finer-grained basis than the DataProxy events.
6493 getConnection : function(){
6494 return this.useAjax ? Roo.Ajax : this.conn;
6498 * Load data from the configured {@link Roo.data.Connection}, read the data object into
6499 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
6500 * process that block using the passed callback.
6501 * @param {Object} params An object containing properties which are to be used as HTTP parameters
6502 * for the request to the remote server.
6503 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6504 * object into a block of Roo.data.Records.
6505 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6506 * The function must be passed <ul>
6507 * <li>The Record block object</li>
6508 * <li>The "arg" argument from the load function</li>
6509 * <li>A boolean success indicator</li>
6511 * @param {Object} scope The scope in which to call the callback
6512 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6514 load : function(params, reader, callback, scope, arg){
6515 if(this.fireEvent("beforeload", this, params) !== false){
6517 params : params || {},
6519 callback : callback,
6524 callback : this.loadResponse,
6528 Roo.applyIf(o, this.conn);
6529 if(this.activeRequest){
6530 Roo.Ajax.abort(this.activeRequest);
6532 this.activeRequest = Roo.Ajax.request(o);
6534 this.conn.request(o);
6537 callback.call(scope||this, null, arg, false);
6542 loadResponse : function(o, success, response){
6543 delete this.activeRequest;
6545 this.fireEvent("loadexception", this, o, response);
6546 o.request.callback.call(o.request.scope, null, o.request.arg, false);
6551 result = o.reader.read(response);
6553 this.fireEvent("loadexception", this, o, response, e);
6554 o.request.callback.call(o.request.scope, null, o.request.arg, false);
6558 this.fireEvent("load", this, o, o.request.arg);
6559 o.request.callback.call(o.request.scope, result, o.request.arg, true);
6563 update : function(dataSet){
6568 updateResponse : function(dataSet){
6573 * Ext JS Library 1.1.1
6574 * Copyright(c) 2006-2007, Ext JS, LLC.
6576 * Originally Released Under LGPL - original licence link has changed is not relivant.
6579 * <script type="text/javascript">
6583 * @class Roo.data.ScriptTagProxy
6584 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
6585 * other than the originating domain of the running page.<br><br>
6587 * <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
6588 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
6590 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
6591 * source code that is used as the source inside a <script> tag.<br><br>
6593 * In order for the browser to process the returned data, the server must wrap the data object
6594 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
6595 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
6596 * depending on whether the callback name was passed:
6599 boolean scriptTag = false;
6600 String cb = request.getParameter("callback");
6603 response.setContentType("text/javascript");
6605 response.setContentType("application/x-json");
6607 Writer out = response.getWriter();
6609 out.write(cb + "(");
6611 out.print(dataBlock.toJsonString());
6618 * @param {Object} config A configuration object.
6620 Roo.data.ScriptTagProxy = function(config){
6621 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
6622 Roo.apply(this, config);
6623 this.head = document.getElementsByTagName("head")[0];
6626 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
6628 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
6630 * @cfg {String} url The URL from which to request the data object.
6633 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
6637 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
6638 * the server the name of the callback function set up by the load call to process the returned data object.
6639 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
6640 * javascript output which calls this named function passing the data object as its only parameter.
6642 callbackParam : "callback",
6644 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
6645 * name to the request.
6650 * Load data from the configured URL, read the data object into
6651 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6652 * process that block using the passed callback.
6653 * @param {Object} params An object containing properties which are to be used as HTTP parameters
6654 * for the request to the remote server.
6655 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6656 * object into a block of Roo.data.Records.
6657 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6658 * The function must be passed <ul>
6659 * <li>The Record block object</li>
6660 * <li>The "arg" argument from the load function</li>
6661 * <li>A boolean success indicator</li>
6663 * @param {Object} scope The scope in which to call the callback
6664 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6666 load : function(params, reader, callback, scope, arg){
6667 if(this.fireEvent("beforeload", this, params) !== false){
6669 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
6672 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
6674 url += "&_dc=" + (new Date().getTime());
6676 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
6679 cb : "stcCallback"+transId,
6680 scriptId : "stcScript"+transId,
6684 callback : callback,
6690 window[trans.cb] = function(o){
6691 conn.handleResponse(o, trans);
6694 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
6696 if(this.autoAbort !== false){
6700 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
6702 var script = document.createElement("script");
6703 script.setAttribute("src", url);
6704 script.setAttribute("type", "text/javascript");
6705 script.setAttribute("id", trans.scriptId);
6706 this.head.appendChild(script);
6710 callback.call(scope||this, null, arg, false);
6715 isLoading : function(){
6716 return this.trans ? true : false;
6720 * Abort the current server request.
6723 if(this.isLoading()){
6724 this.destroyTrans(this.trans);
6729 destroyTrans : function(trans, isLoaded){
6730 this.head.removeChild(document.getElementById(trans.scriptId));
6731 clearTimeout(trans.timeoutId);
6733 window[trans.cb] = undefined;
6735 delete window[trans.cb];
6738 // if hasn't been loaded, wait for load to remove it to prevent script error
6739 window[trans.cb] = function(){
6740 window[trans.cb] = undefined;
6742 delete window[trans.cb];
6749 handleResponse : function(o, trans){
6751 this.destroyTrans(trans, true);
6754 result = trans.reader.readRecords(o);
6756 this.fireEvent("loadexception", this, o, trans.arg, e);
6757 trans.callback.call(trans.scope||window, null, trans.arg, false);
6760 this.fireEvent("load", this, o, trans.arg);
6761 trans.callback.call(trans.scope||window, result, trans.arg, true);
6765 handleFailure : function(trans){
6767 this.destroyTrans(trans, false);
6768 this.fireEvent("loadexception", this, null, trans.arg);
6769 trans.callback.call(trans.scope||window, null, trans.arg, false);
6773 * Ext JS Library 1.1.1
6774 * Copyright(c) 2006-2007, Ext JS, LLC.
6776 * Originally Released Under LGPL - original licence link has changed is not relivant.
6779 * <script type="text/javascript">
6783 * @class Roo.data.JsonReader
6784 * @extends Roo.data.DataReader
6785 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6786 * based on mappings in a provided Roo.data.Record constructor.
6788 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6789 * in the reply previously.
6794 var RecordDef = Roo.data.Record.create([
6795 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6796 {name: 'occupation'} // This field will use "occupation" as the mapping.
6798 var myReader = new Roo.data.JsonReader({
6799 totalProperty: "results", // The property which contains the total dataset size (optional)
6800 root: "rows", // The property which contains an Array of row objects
6801 id: "id" // The property within each row object that provides an ID for the record (optional)
6805 * This would consume a JSON file like this:
6807 { 'results': 2, 'rows': [
6808 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6809 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6812 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6813 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6814 * paged from the remote server.
6815 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6816 * @cfg {String} root name of the property which contains the Array of row objects.
6817 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6819 * Create a new JsonReader
6820 * @param {Object} meta Metadata configuration options
6821 * @param {Object} recordType Either an Array of field definition objects,
6822 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6824 Roo.data.JsonReader = function(meta, recordType){
6827 // set some defaults:
6829 totalProperty: 'total',
6830 successProperty : 'success',
6835 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6837 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6840 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6841 * Used by Store query builder to append _requestMeta to params.
6844 metaFromRemote : false,
6846 * This method is only used by a DataProxy which has retrieved data from a remote server.
6847 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6848 * @return {Object} data A data block which is used by an Roo.data.Store object as
6849 * a cache of Roo.data.Records.
6851 read : function(response){
6852 var json = response.responseText;
6854 var o = /* eval:var:o */ eval("("+json+")");
6856 throw {message: "JsonReader.read: Json object not found"};
6862 this.metaFromRemote = true;
6863 this.meta = o.metaData;
6864 this.recordType = Roo.data.Record.create(o.metaData.fields);
6865 this.onMetaChange(this.meta, this.recordType, o);
6867 return this.readRecords(o);
6870 // private function a store will implement
6871 onMetaChange : function(meta, recordType, o){
6878 simpleAccess: function(obj, subsc) {
6885 getJsonAccessor: function(){
6887 return function(expr) {
6889 return(re.test(expr))
6890 ? new Function("obj", "return obj." + expr)
6900 * Create a data block containing Roo.data.Records from an XML document.
6901 * @param {Object} o An object which contains an Array of row objects in the property specified
6902 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6903 * which contains the total size of the dataset.
6904 * @return {Object} data A data block which is used by an Roo.data.Store object as
6905 * a cache of Roo.data.Records.
6907 readRecords : function(o){
6909 * After any data loads, the raw JSON data is available for further custom processing.
6913 var s = this.meta, Record = this.recordType,
6914 f = Record.prototype.fields, fi = f.items, fl = f.length;
6916 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6918 if(s.totalProperty) {
6919 this.getTotal = this.getJsonAccessor(s.totalProperty);
6921 if(s.successProperty) {
6922 this.getSuccess = this.getJsonAccessor(s.successProperty);
6924 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6926 var g = this.getJsonAccessor(s.id);
6927 this.getId = function(rec) {
6929 return (r === undefined || r === "") ? null : r;
6932 this.getId = function(){return null;};
6935 for(var jj = 0; jj < fl; jj++){
6937 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6938 this.ef[jj] = this.getJsonAccessor(map);
6942 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6943 if(s.totalProperty){
6944 var vt = parseInt(this.getTotal(o), 10);
6949 if(s.successProperty){
6950 var vs = this.getSuccess(o);
6951 if(vs === false || vs === 'false'){
6956 for(var i = 0; i < c; i++){
6959 var id = this.getId(n);
6960 for(var j = 0; j < fl; j++){
6962 var v = this.ef[j](n);
6964 Roo.log('missing convert for ' + f.name);
6968 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6970 var record = new Record(values, id);
6972 records[i] = record;
6978 totalRecords : totalRecords
6983 * Ext JS Library 1.1.1
6984 * Copyright(c) 2006-2007, Ext JS, LLC.
6986 * Originally Released Under LGPL - original licence link has changed is not relivant.
6989 * <script type="text/javascript">
6993 * @class Roo.data.ArrayReader
6994 * @extends Roo.data.DataReader
6995 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6996 * Each element of that Array represents a row of data fields. The
6997 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6998 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
7002 var RecordDef = Roo.data.Record.create([
7003 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
7004 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
7006 var myReader = new Roo.data.ArrayReader({
7007 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
7011 * This would consume an Array like this:
7013 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
7015 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
7017 * Create a new JsonReader
7018 * @param {Object} meta Metadata configuration options.
7019 * @param {Object} recordType Either an Array of field definition objects
7020 * as specified to {@link Roo.data.Record#create},
7021 * or an {@link Roo.data.Record} object
7022 * created using {@link Roo.data.Record#create}.
7024 Roo.data.ArrayReader = function(meta, recordType){
7025 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
7028 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
7030 * Create a data block containing Roo.data.Records from an XML document.
7031 * @param {Object} o An Array of row objects which represents the dataset.
7032 * @return {Object} data A data block which is used by an Roo.data.Store object as
7033 * a cache of Roo.data.Records.
7035 readRecords : function(o){
7036 var sid = this.meta ? this.meta.id : null;
7037 var recordType = this.recordType, fields = recordType.prototype.fields;
7040 for(var i = 0; i < root.length; i++){
7043 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
7044 for(var j = 0, jlen = fields.length; j < jlen; j++){
7045 var f = fields.items[j];
7046 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
7047 var v = n[k] !== undefined ? n[k] : f.defaultValue;
7051 var record = new recordType(values, id);
7053 records[records.length] = record;
7057 totalRecords : records.length
7066 * @class Roo.bootstrap.ComboBox
7067 * @extends Roo.bootstrap.TriggerField
7068 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
7070 * Create a new ComboBox.
7071 * @param {Object} config Configuration options
7073 Roo.bootstrap.ComboBox = function(config){
7074 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
7078 * Fires when the dropdown list is expanded
7079 * @param {Roo.bootstrap.ComboBox} combo This combo box
7084 * Fires when the dropdown list is collapsed
7085 * @param {Roo.bootstrap.ComboBox} combo This combo box
7089 * @event beforeselect
7090 * Fires before a list item is selected. Return false to cancel the selection.
7091 * @param {Roo.bootstrap.ComboBox} combo This combo box
7092 * @param {Roo.data.Record} record The data record returned from the underlying store
7093 * @param {Number} index The index of the selected item in the dropdown list
7095 'beforeselect' : true,
7098 * Fires when a list item is selected
7099 * @param {Roo.bootstrap.ComboBox} combo This combo box
7100 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
7101 * @param {Number} index The index of the selected item in the dropdown list
7105 * @event beforequery
7106 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
7107 * The event object passed has these properties:
7108 * @param {Roo.bootstrap.ComboBox} combo This combo box
7109 * @param {String} query The query
7110 * @param {Boolean} forceAll true to force "all" query
7111 * @param {Boolean} cancel true to cancel the query
7112 * @param {Object} e The query event object
7114 'beforequery': true,
7117 * Fires when the 'add' icon is pressed (add a listener to enable add button)
7118 * @param {Roo.bootstrap.ComboBox} combo This combo box
7123 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
7124 * @param {Roo.bootstrap.ComboBox} combo This combo box
7125 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
7133 this.selectedIndex = -1;
7134 if(this.mode == 'local'){
7135 if(config.queryDelay === undefined){
7136 this.queryDelay = 10;
7138 if(config.minChars === undefined){
7144 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
7147 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
7148 * rendering into an Roo.Editor, defaults to false)
7151 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
7152 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
7155 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
7158 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
7159 * the dropdown list (defaults to undefined, with no header element)
7163 * @cfg {String/Roo.Template} tpl The template to use to render the output
7167 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
7169 listWidth: undefined,
7171 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
7172 * mode = 'remote' or 'text' if mode = 'local')
7174 displayField: undefined,
7176 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
7177 * mode = 'remote' or 'value' if mode = 'local').
7178 * Note: use of a valueField requires the user make a selection
7179 * in order for a value to be mapped.
7181 valueField: undefined,
7185 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
7186 * field's data value (defaults to the underlying DOM element's name)
7188 hiddenName: undefined,
7190 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
7194 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
7196 selectedClass: 'active',
7199 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
7203 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
7204 * anchor positions (defaults to 'tl-bl')
7206 listAlign: 'tl-bl?',
7208 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
7212 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
7213 * query specified by the allQuery config option (defaults to 'query')
7215 triggerAction: 'query',
7217 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
7218 * (defaults to 4, does not apply if editable = false)
7222 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
7223 * delay (typeAheadDelay) if it matches a known value (defaults to false)
7227 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
7228 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
7232 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
7233 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
7237 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
7238 * when editable = true (defaults to false)
7240 selectOnFocus:false,
7242 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
7244 queryParam: 'query',
7246 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
7247 * when mode = 'remote' (defaults to 'Loading...')
7249 loadingText: 'Loading...',
7251 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
7255 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
7259 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
7260 * traditional select (defaults to true)
7264 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
7268 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
7272 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
7273 * listWidth has a higher value)
7277 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
7278 * allow the user to set arbitrary text into the field (defaults to false)
7280 forceSelection:false,
7282 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
7283 * if typeAhead = true (defaults to 250)
7285 typeAheadDelay : 250,
7287 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
7288 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
7290 valueNotFoundText : undefined,
7292 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
7297 * @cfg {Boolean} disableClear Disable showing of clear button.
7299 disableClear : false,
7301 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
7303 alwaysQuery : false,
7309 // element that contains real text value.. (when hidden is used..)
7312 initEvents: function(){
7315 throw "can not find store for combo";
7317 this.store = Roo.factory(this.store, Roo.data);
7321 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
7324 if(this.hiddenName){
7326 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
7328 this.hiddenField.dom.value =
7329 this.hiddenValue !== undefined ? this.hiddenValue :
7330 this.value !== undefined ? this.value : '';
7332 // prevent input submission
7333 this.el.dom.removeAttribute('name');
7334 this.hiddenField.dom.setAttribute('name', this.hiddenName);
7339 // this.el.dom.setAttribute('autocomplete', 'off');
7342 var cls = 'x-combo-list';
7343 this.list = this.el.select('ul',true).first();
7345 //this.list = new Roo.Layer({
7346 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
7349 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
7350 this.list.setWidth(lw);
7352 this.list.on('mouseover', this.onViewOver, this);
7353 this.list.on('mousemove', this.onViewMove, this);
7356 this.list.swallowEvent('mousewheel');
7357 this.assetHeight = 0;
7360 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
7361 this.assetHeight += this.header.getHeight();
7364 this.innerList = this.list.createChild({cls:cls+'-inner'});
7365 this.innerList.on('mouseover', this.onViewOver, this);
7366 this.innerList.on('mousemove', this.onViewMove, this);
7367 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7369 if(this.allowBlank && !this.pageSize && !this.disableClear){
7370 this.footer = this.list.createChild({cls:cls+'-ft'});
7371 this.pageTb = new Roo.Toolbar(this.footer);
7375 this.footer = this.list.createChild({cls:cls+'-ft'});
7376 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
7377 {pageSize: this.pageSize});
7381 if (this.pageTb && this.allowBlank && !this.disableClear) {
7383 this.pageTb.add(new Roo.Toolbar.Fill(), {
7384 cls: 'x-btn-icon x-btn-clear',
7390 _this.onSelect(false, -1);
7395 this.assetHeight += this.footer.getHeight();
7400 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
7403 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
7404 singleSelect:true, store: this.store, selectedClass: this.selectedClass
7406 //this.view.wrapEl.setDisplayed(false);
7407 this.view.on('click', this.onViewClick, this);
7411 this.store.on('beforeload', this.onBeforeLoad, this);
7412 this.store.on('load', this.onLoad, this);
7413 this.store.on('loadexception', this.onLoadException, this);
7416 this.resizer = new Roo.Resizable(this.list, {
7417 pinned:true, handles:'se'
7419 this.resizer.on('resize', function(r, w, h){
7420 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
7422 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
7423 this.restrictHeight();
7425 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
7429 this.editable = true;
7430 this.setEditable(false);
7435 if (typeof(this.events.add.listeners) != 'undefined') {
7437 this.addicon = this.wrap.createChild(
7438 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
7440 this.addicon.on('click', function(e) {
7441 this.fireEvent('add', this);
7444 if (typeof(this.events.edit.listeners) != 'undefined') {
7446 this.editicon = this.wrap.createChild(
7447 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
7449 this.editicon.setStyle('margin-left', '40px');
7451 this.editicon.on('click', function(e) {
7453 // we fire even if inothing is selected..
7454 this.fireEvent('edit', this, this.lastData );
7461 this.keyNav = new Roo.KeyNav(this.inputEl(), {
7463 this.inKeyMode = true;
7467 "down" : function(e){
7468 if(!this.isExpanded()){
7469 this.onTriggerClick();
7471 this.inKeyMode = true;
7476 "enter" : function(e){
7481 "esc" : function(e){
7485 "tab" : function(e){
7488 if(this.fireEvent("specialkey", this, e)){
7489 this.onViewClick(false);
7497 doRelay : function(foo, bar, hname){
7498 if(hname == 'down' || this.scope.isExpanded()){
7499 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
7508 this.queryDelay = Math.max(this.queryDelay || 10,
7509 this.mode == 'local' ? 10 : 250);
7512 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
7515 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
7517 if(this.editable !== false){
7518 this.inputEl().on("keyup", this.onKeyUp, this);
7520 if(this.forceSelection){
7521 this.on('blur', this.doForce, this);
7525 onDestroy : function(){
7527 this.view.setStore(null);
7528 this.view.el.removeAllListeners();
7529 this.view.el.remove();
7530 this.view.purgeListeners();
7533 this.list.dom.innerHTML = '';
7536 this.store.un('beforeload', this.onBeforeLoad, this);
7537 this.store.un('load', this.onLoad, this);
7538 this.store.un('loadexception', this.onLoadException, this);
7540 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
7544 fireKey : function(e){
7545 if(e.isNavKeyPress() && !this.list.isVisible()){
7546 this.fireEvent("specialkey", this, e);
7551 onResize: function(w, h){
7552 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
7554 // if(typeof w != 'number'){
7555 // // we do not handle it!?!?
7558 // var tw = this.trigger.getWidth();
7559 // // tw += this.addicon ? this.addicon.getWidth() : 0;
7560 // // tw += this.editicon ? this.editicon.getWidth() : 0;
7562 // this.inputEl().setWidth( this.adjustWidth('input', x));
7564 // //this.trigger.setStyle('left', x+'px');
7566 // if(this.list && this.listWidth === undefined){
7567 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
7568 // this.list.setWidth(lw);
7569 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7577 * Allow or prevent the user from directly editing the field text. If false is passed,
7578 * the user will only be able to select from the items defined in the dropdown list. This method
7579 * is the runtime equivalent of setting the 'editable' config option at config time.
7580 * @param {Boolean} value True to allow the user to directly edit the field text
7582 setEditable : function(value){
7583 if(value == this.editable){
7586 this.editable = value;
7588 this.inputEl().dom.setAttribute('readOnly', true);
7589 this.inputEl().on('mousedown', this.onTriggerClick, this);
7590 this.inputEl().addClass('x-combo-noedit');
7592 this.inputEl().dom.setAttribute('readOnly', false);
7593 this.inputEl().un('mousedown', this.onTriggerClick, this);
7594 this.inputEl().removeClass('x-combo-noedit');
7599 onBeforeLoad : function(){
7603 //this.innerList.update(this.loadingText ?
7604 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
7605 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
7607 this.restrictHeight();
7608 this.selectedIndex = -1;
7612 onLoad : function(){
7616 if(this.store.getCount() > 0){
7618 this.restrictHeight();
7619 if(this.lastQuery == this.allQuery){
7621 this.inputEl().dom.select();
7623 if(!this.selectByValue(this.value, true)){
7624 this.select(0, true);
7628 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
7629 this.taTask.delay(this.typeAheadDelay);
7633 this.onEmptyResults();
7638 onLoadException : function()
7641 Roo.log(this.store.reader.jsonData);
7642 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7644 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7650 onTypeAhead : function(){
7651 if(this.store.getCount() > 0){
7652 var r = this.store.getAt(0);
7653 var newValue = r.data[this.displayField];
7654 var len = newValue.length;
7655 var selStart = this.getRawValue().length;
7657 if(selStart != len){
7658 this.setRawValue(newValue);
7659 this.selectText(selStart, newValue.length);
7665 onSelect : function(record, index){
7666 if(this.fireEvent('beforeselect', this, record, index) !== false){
7667 this.setFromData(index > -1 ? record.data : false);
7669 this.fireEvent('select', this, record, index);
7674 * Returns the currently selected field value or empty string if no value is set.
7675 * @return {String} value The selected value
7677 getValue : function(){
7678 if(this.valueField){
7679 return typeof this.value != 'undefined' ? this.value : '';
7681 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
7686 * Clears any text/value currently set in the field
7688 clearValue : function(){
7689 if(this.hiddenField){
7690 this.hiddenField.dom.value = '';
7693 this.setRawValue('');
7694 this.lastSelectionText = '';
7699 * Sets the specified value into the field. If the value finds a match, the corresponding record text
7700 * will be displayed in the field. If the value does not match the data value of an existing item,
7701 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
7702 * Otherwise the field will be blank (although the value will still be set).
7703 * @param {String} value The value to match
7705 setValue : function(v){
7707 if(this.valueField){
7708 var r = this.findRecord(this.valueField, v);
7710 text = r.data[this.displayField];
7711 }else if(this.valueNotFoundText !== undefined){
7712 text = this.valueNotFoundText;
7715 this.lastSelectionText = text;
7716 if(this.hiddenField){
7717 this.hiddenField.dom.value = v;
7719 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
7723 * @property {Object} the last set data for the element
7728 * Sets the value of the field based on a object which is related to the record format for the store.
7729 * @param {Object} value the value to set as. or false on reset?
7731 setFromData : function(o){
7732 var dv = ''; // display value
7733 var vv = ''; // value value..
7735 if (this.displayField) {
7736 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
7738 // this is an error condition!!!
7739 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
7742 if(this.valueField){
7743 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
7745 if(this.hiddenField){
7746 this.hiddenField.dom.value = vv;
7748 this.lastSelectionText = dv;
7749 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7753 // no hidden field.. - we store the value in 'value', but still display
7754 // display field!!!!
7755 this.lastSelectionText = dv;
7756 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7763 // overridden so that last data is reset..
7764 this.setValue(this.originalValue);
7765 this.clearInvalid();
7766 this.lastData = false;
7768 this.view.clearSelections();
7772 findRecord : function(prop, value){
7774 if(this.store.getCount() > 0){
7775 this.store.each(function(r){
7776 if(r.data[prop] == value){
7788 // returns hidden if it's set..
7789 if (!this.rendered) {return ''};
7790 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
7794 onViewMove : function(e, t){
7795 this.inKeyMode = false;
7799 onViewOver : function(e, t){
7800 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
7803 var item = this.view.findItemFromChild(t);
7805 var index = this.view.indexOf(item);
7806 this.select(index, false);
7811 onViewClick : function(doFocus)
7813 var index = this.view.getSelectedIndexes()[0];
7814 var r = this.store.getAt(index);
7816 this.onSelect(r, index);
7818 if(doFocus !== false && !this.blockFocus){
7819 this.inputEl().focus();
7824 restrictHeight : function(){
7825 //this.innerList.dom.style.height = '';
7826 //var inner = this.innerList.dom;
7827 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
7828 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
7829 //this.list.beginUpdate();
7830 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
7831 this.list.alignTo(this.inputEl(), this.listAlign);
7832 //this.list.endUpdate();
7836 onEmptyResults : function(){
7841 * Returns true if the dropdown list is expanded, else false.
7843 isExpanded : function(){
7844 return this.list.isVisible();
7848 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
7849 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7850 * @param {String} value The data value of the item to select
7851 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7852 * selected item if it is not currently in view (defaults to true)
7853 * @return {Boolean} True if the value matched an item in the list, else false
7855 selectByValue : function(v, scrollIntoView){
7856 if(v !== undefined && v !== null){
7857 var r = this.findRecord(this.valueField || this.displayField, v);
7859 this.select(this.store.indexOf(r), scrollIntoView);
7867 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
7868 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7869 * @param {Number} index The zero-based index of the list item to select
7870 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7871 * selected item if it is not currently in view (defaults to true)
7873 select : function(index, scrollIntoView){
7874 this.selectedIndex = index;
7875 this.view.select(index);
7876 if(scrollIntoView !== false){
7877 var el = this.view.getNode(index);
7879 //this.innerList.scrollChildIntoView(el, false);
7886 selectNext : function(){
7887 var ct = this.store.getCount();
7889 if(this.selectedIndex == -1){
7891 }else if(this.selectedIndex < ct-1){
7892 this.select(this.selectedIndex+1);
7898 selectPrev : function(){
7899 var ct = this.store.getCount();
7901 if(this.selectedIndex == -1){
7903 }else if(this.selectedIndex != 0){
7904 this.select(this.selectedIndex-1);
7910 onKeyUp : function(e){
7911 if(this.editable !== false && !e.isSpecialKey()){
7912 this.lastKey = e.getKey();
7913 this.dqTask.delay(this.queryDelay);
7918 validateBlur : function(){
7919 return !this.list || !this.list.isVisible();
7923 initQuery : function(){
7924 this.doQuery(this.getRawValue());
7928 doForce : function(){
7929 if(this.el.dom.value.length > 0){
7931 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
7937 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
7938 * query allowing the query action to be canceled if needed.
7939 * @param {String} query The SQL query to execute
7940 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
7941 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
7942 * saved in the current store (defaults to false)
7944 doQuery : function(q, forceAll){
7945 if(q === undefined || q === null){
7954 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
7958 forceAll = qe.forceAll;
7959 if(forceAll === true || (q.length >= this.minChars)){
7960 if(this.lastQuery != q || this.alwaysQuery){
7962 if(this.mode == 'local'){
7963 this.selectedIndex = -1;
7965 this.store.clearFilter();
7967 this.store.filter(this.displayField, q);
7971 this.store.baseParams[this.queryParam] = q;
7973 params: this.getParams(q)
7978 this.selectedIndex = -1;
7985 getParams : function(q){
7987 //p[this.queryParam] = q;
7990 p.limit = this.pageSize;
7996 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
7998 collapse : function(){
7999 if(!this.isExpanded()){
8003 Roo.get(document).un('mousedown', this.collapseIf, this);
8004 Roo.get(document).un('mousewheel', this.collapseIf, this);
8005 if (!this.editable) {
8006 Roo.get(document).un('keydown', this.listKeyPress, this);
8008 this.fireEvent('collapse', this);
8012 collapseIf : function(e){
8013 if(!e.within(this.el) && !e.within(this.el)){
8019 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
8021 expand : function(){
8023 if(this.isExpanded() || !this.hasFocus){
8026 this.list.alignTo(this.inputEl(), this.listAlign);
8028 Roo.get(document).on('mousedown', this.collapseIf, this);
8029 Roo.get(document).on('mousewheel', this.collapseIf, this);
8030 if (!this.editable) {
8031 Roo.get(document).on('keydown', this.listKeyPress, this);
8034 this.fireEvent('expand', this);
8038 // Implements the default empty TriggerField.onTriggerClick function
8039 onTriggerClick : function()
8041 Roo.log('trigger click');
8046 if(this.isExpanded()){
8048 if (!this.blockFocus) {
8049 this.inputEl().focus();
8053 this.hasFocus = true;
8054 if(this.triggerAction == 'all') {
8055 this.doQuery(this.allQuery, true);
8057 this.doQuery(this.getRawValue());
8059 if (!this.blockFocus) {
8060 this.inputEl().focus();
8064 listKeyPress : function(e)
8066 //Roo.log('listkeypress');
8067 // scroll to first matching element based on key pres..
8068 if (e.isSpecialKey()) {
8071 var k = String.fromCharCode(e.getKey()).toUpperCase();
8074 var csel = this.view.getSelectedNodes();
8075 var cselitem = false;
8077 var ix = this.view.indexOf(csel[0]);
8078 cselitem = this.store.getAt(ix);
8079 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
8085 this.store.each(function(v) {
8087 // start at existing selection.
8088 if (cselitem.id == v.id) {
8094 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
8095 match = this.store.indexOf(v);
8101 if (match === false) {
8102 return true; // no more action?
8105 this.view.select(match);
8106 var sn = Roo.get(this.view.getSelectedNodes()[0])
8107 //sn.scrollIntoView(sn.dom.parentNode, false);
8111 * @cfg {Boolean} grow
8115 * @cfg {Number} growMin
8119 * @cfg {Number} growMax
8128 * Ext JS Library 1.1.1
8129 * Copyright(c) 2006-2007, Ext JS, LLC.
8131 * Originally Released Under LGPL - original licence link has changed is not relivant.
8134 * <script type="text/javascript">
8139 * @extends Roo.util.Observable
8140 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
8141 * This class also supports single and multi selection modes. <br>
8142 * Create a data model bound view:
8144 var store = new Roo.data.Store(...);
8146 var view = new Roo.View({
8148 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
8151 selectedClass: "ydataview-selected",
8155 // listen for node click?
8156 view.on("click", function(vw, index, node, e){
8157 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
8161 dataModel.load("foobar.xml");
8163 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
8165 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
8166 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
8168 * Note: old style constructor is still suported (container, template, config)
8172 * @param {Object} config The config object
8175 Roo.View = function(config, depreciated_tpl, depreciated_config){
8177 if (typeof(depreciated_tpl) == 'undefined') {
8178 // new way.. - universal constructor.
8179 Roo.apply(this, config);
8180 this.el = Roo.get(this.el);
8183 this.el = Roo.get(config);
8184 this.tpl = depreciated_tpl;
8185 Roo.apply(this, depreciated_config);
8187 this.wrapEl = this.el.wrap().wrap();
8188 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
8191 if(typeof(this.tpl) == "string"){
8192 this.tpl = new Roo.Template(this.tpl);
8194 // support xtype ctors..
8195 this.tpl = new Roo.factory(this.tpl, Roo);
8207 * @event beforeclick
8208 * Fires before a click is processed. Returns false to cancel the default action.
8209 * @param {Roo.View} this
8210 * @param {Number} index The index of the target node
8211 * @param {HTMLElement} node The target node
8212 * @param {Roo.EventObject} e The raw event object
8214 "beforeclick" : true,
8217 * Fires when a template node is clicked.
8218 * @param {Roo.View} this
8219 * @param {Number} index The index of the target node
8220 * @param {HTMLElement} node The target node
8221 * @param {Roo.EventObject} e The raw event object
8226 * Fires when a template node is double clicked.
8227 * @param {Roo.View} this
8228 * @param {Number} index The index of the target node
8229 * @param {HTMLElement} node The target node
8230 * @param {Roo.EventObject} e The raw event object
8234 * @event contextmenu
8235 * Fires when a template node is right clicked.
8236 * @param {Roo.View} this
8237 * @param {Number} index The index of the target node
8238 * @param {HTMLElement} node The target node
8239 * @param {Roo.EventObject} e The raw event object
8241 "contextmenu" : true,
8243 * @event selectionchange
8244 * Fires when the selected nodes change.
8245 * @param {Roo.View} this
8246 * @param {Array} selections Array of the selected nodes
8248 "selectionchange" : true,
8251 * @event beforeselect
8252 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
8253 * @param {Roo.View} this
8254 * @param {HTMLElement} node The node to be selected
8255 * @param {Array} selections Array of currently selected nodes
8257 "beforeselect" : true,
8259 * @event preparedata
8260 * Fires on every row to render, to allow you to change the data.
8261 * @param {Roo.View} this
8262 * @param {Object} data to be rendered (change this)
8264 "preparedata" : true
8272 "click": this.onClick,
8273 "dblclick": this.onDblClick,
8274 "contextmenu": this.onContextMenu,
8278 this.selections = [];
8280 this.cmp = new Roo.CompositeElementLite([]);
8282 this.store = Roo.factory(this.store, Roo.data);
8283 this.setStore(this.store, true);
8286 if ( this.footer && this.footer.xtype) {
8288 var fctr = this.wrapEl.appendChild(document.createElement("div"));
8290 this.footer.dataSource = this.store
8291 this.footer.container = fctr;
8292 this.footer = Roo.factory(this.footer, Roo);
8293 fctr.insertFirst(this.el);
8295 // this is a bit insane - as the paging toolbar seems to detach the el..
8296 // dom.parentNode.parentNode.parentNode
8297 // they get detached?
8301 Roo.View.superclass.constructor.call(this);
8306 Roo.extend(Roo.View, Roo.util.Observable, {
8309 * @cfg {Roo.data.Store} store Data store to load data from.
8314 * @cfg {String|Roo.Element} el The container element.
8319 * @cfg {String|Roo.Template} tpl The template used by this View
8323 * @cfg {String} dataName the named area of the template to use as the data area
8324 * Works with domtemplates roo-name="name"
8328 * @cfg {String} selectedClass The css class to add to selected nodes
8330 selectedClass : "x-view-selected",
8332 * @cfg {String} emptyText The empty text to show when nothing is loaded.
8337 * @cfg {String} text to display on mask (default Loading)
8341 * @cfg {Boolean} multiSelect Allow multiple selection
8343 multiSelect : false,
8345 * @cfg {Boolean} singleSelect Allow single selection
8347 singleSelect: false,
8350 * @cfg {Boolean} toggleSelect - selecting
8352 toggleSelect : false,
8355 * Returns the element this view is bound to.
8356 * @return {Roo.Element}
8365 * Refreshes the view. - called by datachanged on the store. - do not call directly.
8367 refresh : function(){
8370 // if we are using something like 'domtemplate', then
8371 // the what gets used is:
8372 // t.applySubtemplate(NAME, data, wrapping data..)
8373 // the outer template then get' applied with
8374 // the store 'extra data'
8375 // and the body get's added to the
8376 // roo-name="data" node?
8377 // <span class='roo-tpl-{name}'></span> ?????
8381 this.clearSelections();
8384 var records = this.store.getRange();
8385 if(records.length < 1) {
8387 // is this valid?? = should it render a template??
8389 this.el.update(this.emptyText);
8393 if (this.dataName) {
8394 this.el.update(t.apply(this.store.meta)); //????
8395 el = this.el.child('.roo-tpl-' + this.dataName);
8398 for(var i = 0, len = records.length; i < len; i++){
8399 var data = this.prepareData(records[i].data, i, records[i]);
8400 this.fireEvent("preparedata", this, data, i, records[i]);
8401 html[html.length] = Roo.util.Format.trim(
8403 t.applySubtemplate(this.dataName, data, this.store.meta) :
8410 el.update(html.join(""));
8411 this.nodes = el.dom.childNodes;
8412 this.updateIndexes(0);
8416 * Function to override to reformat the data that is sent to
8417 * the template for each node.
8418 * DEPRICATED - use the preparedata event handler.
8419 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
8420 * a JSON object for an UpdateManager bound view).
8422 prepareData : function(data, index, record)
8424 this.fireEvent("preparedata", this, data, index, record);
8428 onUpdate : function(ds, record){
8429 this.clearSelections();
8430 var index = this.store.indexOf(record);
8431 var n = this.nodes[index];
8432 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
8433 n.parentNode.removeChild(n);
8434 this.updateIndexes(index, index);
8440 onAdd : function(ds, records, index)
8442 this.clearSelections();
8443 if(this.nodes.length == 0){
8447 var n = this.nodes[index];
8448 for(var i = 0, len = records.length; i < len; i++){
8449 var d = this.prepareData(records[i].data, i, records[i]);
8451 this.tpl.insertBefore(n, d);
8454 this.tpl.append(this.el, d);
8457 this.updateIndexes(index);
8460 onRemove : function(ds, record, index){
8461 this.clearSelections();
8462 var el = this.dataName ?
8463 this.el.child('.roo-tpl-' + this.dataName) :
8465 el.dom.removeChild(this.nodes[index]);
8466 this.updateIndexes(index);
8470 * Refresh an individual node.
8471 * @param {Number} index
8473 refreshNode : function(index){
8474 this.onUpdate(this.store, this.store.getAt(index));
8477 updateIndexes : function(startIndex, endIndex){
8478 var ns = this.nodes;
8479 startIndex = startIndex || 0;
8480 endIndex = endIndex || ns.length - 1;
8481 for(var i = startIndex; i <= endIndex; i++){
8482 ns[i].nodeIndex = i;
8487 * Changes the data store this view uses and refresh the view.
8488 * @param {Store} store
8490 setStore : function(store, initial){
8491 if(!initial && this.store){
8492 this.store.un("datachanged", this.refresh);
8493 this.store.un("add", this.onAdd);
8494 this.store.un("remove", this.onRemove);
8495 this.store.un("update", this.onUpdate);
8496 this.store.un("clear", this.refresh);
8497 this.store.un("beforeload", this.onBeforeLoad);
8498 this.store.un("load", this.onLoad);
8499 this.store.un("loadexception", this.onLoad);
8503 store.on("datachanged", this.refresh, this);
8504 store.on("add", this.onAdd, this);
8505 store.on("remove", this.onRemove, this);
8506 store.on("update", this.onUpdate, this);
8507 store.on("clear", this.refresh, this);
8508 store.on("beforeload", this.onBeforeLoad, this);
8509 store.on("load", this.onLoad, this);
8510 store.on("loadexception", this.onLoad, this);
8518 * onbeforeLoad - masks the loading area.
8521 onBeforeLoad : function()
8524 this.el.mask(this.mask ? this.mask : "Loading" );
8526 onLoad : function ()
8533 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
8534 * @param {HTMLElement} node
8535 * @return {HTMLElement} The template node
8537 findItemFromChild : function(node){
8538 var el = this.dataName ?
8539 this.el.child('.roo-tpl-' + this.dataName,true) :
8542 if(!node || node.parentNode == el){
8545 var p = node.parentNode;
8546 while(p && p != el){
8547 if(p.parentNode == el){
8556 onClick : function(e){
8557 var item = this.findItemFromChild(e.getTarget());
8559 var index = this.indexOf(item);
8560 if(this.onItemClick(item, index, e) !== false){
8561 this.fireEvent("click", this, index, item, e);
8564 this.clearSelections();
8569 onContextMenu : function(e){
8570 var item = this.findItemFromChild(e.getTarget());
8572 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
8577 onDblClick : function(e){
8578 var item = this.findItemFromChild(e.getTarget());
8580 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
8584 onItemClick : function(item, index, e)
8586 if(this.fireEvent("beforeclick", this, index, item, e) === false){
8589 if (this.toggleSelect) {
8590 var m = this.isSelected(item) ? 'unselect' : 'select';
8593 _t[m](item, true, false);
8596 if(this.multiSelect || this.singleSelect){
8597 if(this.multiSelect && e.shiftKey && this.lastSelection){
8598 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
8600 this.select(item, this.multiSelect && e.ctrlKey);
8601 this.lastSelection = item;
8609 * Get the number of selected nodes.
8612 getSelectionCount : function(){
8613 return this.selections.length;
8617 * Get the currently selected nodes.
8618 * @return {Array} An array of HTMLElements
8620 getSelectedNodes : function(){
8621 return this.selections;
8625 * Get the indexes of the selected nodes.
8628 getSelectedIndexes : function(){
8629 var indexes = [], s = this.selections;
8630 for(var i = 0, len = s.length; i < len; i++){
8631 indexes.push(s[i].nodeIndex);
8637 * Clear all selections
8638 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
8640 clearSelections : function(suppressEvent){
8641 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
8642 this.cmp.elements = this.selections;
8643 this.cmp.removeClass(this.selectedClass);
8644 this.selections = [];
8646 this.fireEvent("selectionchange", this, this.selections);
8652 * Returns true if the passed node is selected
8653 * @param {HTMLElement/Number} node The node or node index
8656 isSelected : function(node){
8657 var s = this.selections;
8661 node = this.getNode(node);
8662 return s.indexOf(node) !== -1;
8667 * @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
8668 * @param {Boolean} keepExisting (optional) true to keep existing selections
8669 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8671 select : function(nodeInfo, keepExisting, suppressEvent){
8672 if(nodeInfo instanceof Array){
8674 this.clearSelections(true);
8676 for(var i = 0, len = nodeInfo.length; i < len; i++){
8677 this.select(nodeInfo[i], true, true);
8681 var node = this.getNode(nodeInfo);
8682 if(!node || this.isSelected(node)){
8683 return; // already selected.
8686 this.clearSelections(true);
8688 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
8689 Roo.fly(node).addClass(this.selectedClass);
8690 this.selections.push(node);
8692 this.fireEvent("selectionchange", this, this.selections);
8700 * @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
8701 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
8702 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8704 unselect : function(nodeInfo, keepExisting, suppressEvent)
8706 if(nodeInfo instanceof Array){
8707 Roo.each(this.selections, function(s) {
8708 this.unselect(s, nodeInfo);
8712 var node = this.getNode(nodeInfo);
8713 if(!node || !this.isSelected(node)){
8714 Roo.log("not selected");
8715 return; // not selected.
8719 Roo.each(this.selections, function(s) {
8721 Roo.fly(node).removeClass(this.selectedClass);
8728 this.selections= ns;
8729 this.fireEvent("selectionchange", this, this.selections);
8733 * Gets a template node.
8734 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8735 * @return {HTMLElement} The node or null if it wasn't found
8737 getNode : function(nodeInfo){
8738 if(typeof nodeInfo == "string"){
8739 return document.getElementById(nodeInfo);
8740 }else if(typeof nodeInfo == "number"){
8741 return this.nodes[nodeInfo];
8747 * Gets a range template nodes.
8748 * @param {Number} startIndex
8749 * @param {Number} endIndex
8750 * @return {Array} An array of nodes
8752 getNodes : function(start, end){
8753 var ns = this.nodes;
8755 end = typeof end == "undefined" ? ns.length - 1 : end;
8758 for(var i = start; i <= end; i++){
8762 for(var i = start; i >= end; i--){
8770 * Finds the index of the passed node
8771 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8772 * @return {Number} The index of the node or -1
8774 indexOf : function(node){
8775 node = this.getNode(node);
8776 if(typeof node.nodeIndex == "number"){
8777 return node.nodeIndex;
8779 var ns = this.nodes;
8780 for(var i = 0, len = ns.length; i < len; i++){
8791 * based on jquery fullcalendar
8795 Roo.bootstrap = Roo.bootstrap || {};
8797 * @class Roo.bootstrap.Calendar
8798 * @extends Roo.bootstrap.Component
8799 * Bootstrap Calendar class
8800 * @cfg {Boolean} loadMask (true|false) default false
8803 * Create a new Container
8804 * @param {Object} config The config object
8809 Roo.bootstrap.Calendar = function(config){
8810 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
8814 * Fires when a date is selected
8815 * @param {DatePicker} this
8816 * @param {Date} date The selected date
8820 * @event monthchange
8821 * Fires when the displayed month changes
8822 * @param {DatePicker} this
8823 * @param {Date} date The selected month
8825 'monthchange': true,
8828 * Fires when mouse over an event
8829 * @param {Calendar} this
8830 * @param {event} Event
8835 * Fires when the mouse leaves an
8836 * @param {Calendar} this
8842 * Fires when the mouse click an
8843 * @param {Calendar} this
8852 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
8855 * @cfg {Number} startDay
8856 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
8862 getAutoCreate : function(){
8865 var fc_button = function(name, corner, style, content ) {
8866 return Roo.apply({},{
8868 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
8870 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
8873 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
8881 style : 'width:100%',
8888 cls : 'fc-header-left',
8890 fc_button('prev', 'left', 'arrow', '‹' ),
8891 fc_button('next', 'right', 'arrow', '›' ),
8892 { tag: 'span', cls: 'fc-header-space' },
8893 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
8901 cls : 'fc-header-center',
8905 cls: 'fc-header-title',
8908 html : 'month / year'
8916 cls : 'fc-header-right',
8918 /* fc_button('month', 'left', '', 'month' ),
8919 fc_button('week', '', '', 'week' ),
8920 fc_button('day', 'right', '', 'day' )
8932 var cal_heads = function() {
8934 // fixme - handle this.
8936 for (var i =0; i < Date.dayNames.length; i++) {
8937 var d = Date.dayNames[i];
8940 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
8941 html : d.substring(0,3)
8945 ret[0].cls += ' fc-first';
8946 ret[6].cls += ' fc-last';
8949 var cal_cell = function(n) {
8952 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
8957 cls: 'fc-day-number',
8961 cls: 'fc-day-content',
8965 style: 'position: relative;' // height: 17px;
8977 var cal_rows = function() {
8980 for (var r = 0; r < 6; r++) {
8987 for (var i =0; i < Date.dayNames.length; i++) {
8988 var d = Date.dayNames[i];
8989 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
8992 row.cn[0].cls+=' fc-first';
8993 row.cn[0].cn[0].style = 'min-height:90px';
8994 row.cn[6].cls+=' fc-last';
8998 ret[0].cls += ' fc-first';
8999 ret[4].cls += ' fc-prev-last';
9000 ret[5].cls += ' fc-last';
9007 cls: 'fc-border-separate',
9008 style : 'width:100%',
9016 cls : 'fc-first fc-last',
9035 style : "position: relative;",
9038 cls : 'fc-view fc-view-month fc-grid',
9039 style : 'position: relative',
9040 unselectable : 'on',
9043 cls : 'fc-event-container',
9044 style : 'position:absolute;z-index:8;top:0;left:0;'
9062 initEvents : function()
9065 throw "can not find store for calendar";
9071 style: "text-align:center",
9075 style: "background-color:white;width:50%;margin:250 auto",
9079 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
9090 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
9092 var size = this.el.select('.fc-content', true).first().getSize();
9093 this.maskEl.setSize(size.width, size.height);
9094 this.maskEl.enableDisplayMode("block");
9099 this.store = Roo.factory(this.store, Roo.data);
9100 this.store.on('load', this.onLoad, this);
9101 this.store.on('beforeload', this.onBeforeLoad, this);
9105 this.cells = this.el.select('.fc-day',true);
9106 //Roo.log(this.cells);
9107 this.textNodes = this.el.query('.fc-day-number');
9108 this.cells.addClassOnOver('fc-state-hover');
9110 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
9111 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
9112 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
9113 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
9115 this.on('monthchange', this.onMonthChange, this);
9117 // this.update(new Date().clearTime());
9120 resize : function() {
9121 var sz = this.el.getSize();
9123 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
9124 this.el.select('.fc-day-content div',true).setHeight(34);
9129 showPrevMonth : function(e){
9130 this.update(this.activeDate.add("mo", -1));
9132 showToday : function(e){
9133 this.update(new Date().clearTime());
9136 showNextMonth : function(e){
9137 this.update(this.activeDate.add("mo", 1));
9141 showPrevYear : function(){
9142 this.update(this.activeDate.add("y", -1));
9146 showNextYear : function(){
9147 this.update(this.activeDate.add("y", 1));
9152 update : function(date)
9154 var vd = this.activeDate;
9155 this.activeDate = date;
9156 // if(vd && this.el){
9157 // var t = date.getTime();
9158 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
9159 // Roo.log('using add remove');
9161 // this.fireEvent('monthchange', this, date);
9163 // this.cells.removeClass("fc-state-highlight");
9164 // this.cells.each(function(c){
9165 // if(c.dateValue == t){
9166 // c.addClass("fc-state-highlight");
9167 // setTimeout(function(){
9168 // try{c.dom.firstChild.focus();}catch(e){}
9178 var days = date.getDaysInMonth();
9180 var firstOfMonth = date.getFirstDateOfMonth();
9181 var startingPos = firstOfMonth.getDay()-this.startDay;
9183 if(startingPos < this.startDay){
9187 var pm = date.add(Date.MONTH, -1);
9188 var prevStart = pm.getDaysInMonth()-startingPos;
9190 this.cells = this.el.select('.fc-day',true);
9191 this.textNodes = this.el.query('.fc-day-number');
9192 this.cells.addClassOnOver('fc-state-hover');
9194 var cells = this.cells.elements;
9195 var textEls = this.textNodes;
9197 Roo.each(cells, function(cell){
9198 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
9201 days += startingPos;
9203 // convert everything to numbers so it's fast
9205 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
9208 //Roo.log(prevStart);
9210 var today = new Date().clearTime().getTime();
9211 var sel = date.clearTime().getTime();
9212 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
9213 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
9214 var ddMatch = this.disabledDatesRE;
9215 var ddText = this.disabledDatesText;
9216 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
9217 var ddaysText = this.disabledDaysText;
9218 var format = this.format;
9220 var setCellClass = function(cal, cell){
9222 //Roo.log('set Cell Class');
9224 var t = d.getTime();
9230 cell.className += " fc-today";
9231 cell.className += " fc-state-highlight";
9232 cell.title = cal.todayText;
9235 // disable highlight in other month..
9236 //cell.className += " fc-state-highlight";
9241 cell.className = " fc-state-disabled";
9242 cell.title = cal.minText;
9246 cell.className = " fc-state-disabled";
9247 cell.title = cal.maxText;
9251 if(ddays.indexOf(d.getDay()) != -1){
9252 cell.title = ddaysText;
9253 cell.className = " fc-state-disabled";
9256 if(ddMatch && format){
9257 var fvalue = d.dateFormat(format);
9258 if(ddMatch.test(fvalue)){
9259 cell.title = ddText.replace("%0", fvalue);
9260 cell.className = " fc-state-disabled";
9264 if (!cell.initialClassName) {
9265 cell.initialClassName = cell.dom.className;
9268 cell.dom.className = cell.initialClassName + ' ' + cell.className;
9273 for(; i < startingPos; i++) {
9274 textEls[i].innerHTML = (++prevStart);
9275 d.setDate(d.getDate()+1);
9277 cells[i].className = "fc-past fc-other-month";
9278 setCellClass(this, cells[i]);
9283 for(; i < days; i++){
9284 intDay = i - startingPos + 1;
9285 textEls[i].innerHTML = (intDay);
9286 d.setDate(d.getDate()+1);
9288 cells[i].className = ''; // "x-date-active";
9289 setCellClass(this, cells[i]);
9293 for(; i < 42; i++) {
9294 textEls[i].innerHTML = (++extraDays);
9295 d.setDate(d.getDate()+1);
9297 cells[i].className = "fc-future fc-other-month";
9298 setCellClass(this, cells[i]);
9301 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
9303 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
9305 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
9306 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
9309 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
9310 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
9313 this.fireEvent('monthchange', this, date);
9317 if(!this.internalRender){
9318 var main = this.el.dom.firstChild;
9319 var w = main.offsetWidth;
9320 this.el.setWidth(w + this.el.getBorderWidth("lr"));
9321 Roo.fly(main).setWidth(w);
9322 this.internalRender = true;
9323 // opera does not respect the auto grow header center column
9324 // then, after it gets a width opera refuses to recalculate
9325 // without a second pass
9326 if(Roo.isOpera && !this.secondPass){
9327 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
9328 this.secondPass = true;
9329 this.update.defer(10, this, [date]);
9336 findCell : function(dt) {
9337 dt = dt.clearTime().getTime();
9339 this.cells.each(function(c){
9340 //Roo.log("check " +c.dateValue + '?=' + dt);
9341 if(c.dateValue == dt){
9351 findCells : function(ev) {
9352 var s = ev.start.clone().clearTime().getTime();
9354 var e= ev.end.clone().clearTime().getTime();
9357 this.cells.each(function(c){
9358 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
9360 if(c.dateValue > e){
9363 if(c.dateValue < s){
9372 findBestRow: function(cells)
9376 for (var i =0 ; i < cells.length;i++) {
9377 ret = Math.max(cells[i].rows || 0,ret);
9384 addItem : function(ev)
9386 // look for vertical location slot in
9387 var cells = this.findCells(ev);
9389 ev.row = this.findBestRow(cells);
9391 // work out the location.
9395 for(var i =0; i < cells.length; i++) {
9403 if (crow.start.getY() == cells[i].getY()) {
9405 crow.end = cells[i];
9421 for (var i = 0; i < cells.length;i++) {
9422 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
9426 this.calevents.push(ev);
9429 clearEvents: function() {
9431 if(!this.calevents){
9435 Roo.each(this.cells.elements, function(c){
9439 Roo.each(this.calevents, function(e) {
9440 Roo.each(e.els, function(el) {
9441 el.un('mouseenter' ,this.onEventEnter, this);
9442 el.un('mouseleave' ,this.onEventLeave, this);
9449 renderEvents: function()
9451 // first make sure there is enough space..
9453 this.cells.each(function(c) {
9455 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
9458 for (var e = 0; e < this.calevents.length; e++) {
9459 var ev = this.calevents[e];
9460 var cells = ev.cells;
9463 for(var i =0; i < rows.length; i++) {
9466 // how many rows should it span..
9469 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
9470 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
9472 unselectable : "on",
9475 cls: 'fc-event-inner',
9479 cls: 'fc-event-time',
9480 html : cells.length > 1 ? '' : ev.time
9484 cls: 'fc-event-title',
9485 html : String.format('{0}', ev.title)
9492 cls: 'ui-resizable-handle ui-resizable-e',
9493 html : '  '
9499 cfg.cls += ' fc-event-start';
9501 if ((i+1) == rows.length) {
9502 cfg.cls += ' fc-event-end';
9505 var ctr = this.el.select('.fc-event-container',true).first();
9506 var cg = ctr.createChild(cfg);
9508 cg.on('mouseenter' ,this.onEventEnter, this, ev);
9509 cg.on('mouseleave' ,this.onEventLeave, this, ev);
9510 cg.on('click', this.onEventClick, this, ev);
9514 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
9515 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
9517 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
9518 cg.setWidth(ebox.right - sbox.x -2);
9526 onEventEnter: function (e, el,event,d) {
9527 this.fireEvent('evententer', this, el, event);
9530 onEventLeave: function (e, el,event,d) {
9531 this.fireEvent('eventleave', this, el, event);
9534 onEventClick: function (e, el,event,d) {
9535 this.fireEvent('eventclick', this, el, event);
9538 onMonthChange: function () {
9544 this.calevents = [];
9546 if(this.store.getCount() > 0){
9547 this.store.data.each(function(d){
9550 start: new Date(d.data.start_dt),
9551 end : new Date(d.data.end_dt),
9552 time : d.data.start_time,
9553 title : d.data.title,
9554 description : d.data.description,
9555 venue : d.data.venue
9560 this.renderEvents();
9567 onBeforeLoad: function()
9586 * @class Roo.bootstrap.Popover
9587 * @extends Roo.bootstrap.Component
9588 * Bootstrap Popover class
9589 * @cfg {String} html contents of the popover (or false to use children..)
9590 * @cfg {String} title of popover (or false to hide)
9591 * @cfg {String} placement how it is placed
9592 * @cfg {String} trigger click || hover (or false to trigger manually)
9593 * @cfg {String} over what (parent or false to trigger manually.)
9596 * Create a new Popover
9597 * @param {Object} config The config object
9600 Roo.bootstrap.Popover = function(config){
9601 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
9604 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
9606 title: 'Fill in a title',
9609 placement : 'right',
9610 trigger : 'hover', // hover
9614 can_build_overlaid : false,
9616 getChildContainer : function()
9618 return this.el.select('.popover-content',true).first();
9621 getAutoCreate : function(){
9622 Roo.log('make popover?');
9624 cls : 'popover roo-dynamic',
9625 style: 'display:block',
9631 cls : 'popover-inner',
9635 cls: 'popover-title',
9639 cls : 'popover-content',
9650 setTitle: function(str)
9652 this.el.select('.popover-title',true).first().dom.innerHTML = str;
9654 setContent: function(str)
9656 this.el.select('.popover-content',true).first().dom.innerHTML = str;
9658 // as it get's added to the bottom of the page.
9659 onRender : function(ct, position)
9661 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
9663 var cfg = Roo.apply({}, this.getAutoCreate());
9667 cfg.cls += ' ' + this.cls;
9670 cfg.style = this.style;
9672 Roo.log("adding to ")
9673 this.el = Roo.get(document.body).createChild(cfg, position);
9679 initEvents : function()
9681 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
9682 this.el.enableDisplayMode('block');
9684 if (this.over === false) {
9687 if (this.triggers === false) {
9690 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9691 var triggers = this.trigger ? this.trigger.split(' ') : [];
9692 Roo.each(triggers, function(trigger) {
9694 if (trigger == 'click') {
9695 on_el.on('click', this.toggle, this);
9696 } else if (trigger != 'manual') {
9697 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
9698 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
9700 on_el.on(eventIn ,this.enter, this);
9701 on_el.on(eventOut, this.leave, this);
9712 toggle : function () {
9713 this.hoverState == 'in' ? this.leave() : this.enter();
9716 enter : function () {
9719 clearTimeout(this.timeout);
9721 this.hoverState = 'in'
9723 if (!this.delay || !this.delay.show) {
9728 this.timeout = setTimeout(function () {
9729 if (_t.hoverState == 'in') {
9734 leave : function() {
9735 clearTimeout(this.timeout);
9737 this.hoverState = 'out'
9739 if (!this.delay || !this.delay.hide) {
9744 this.timeout = setTimeout(function () {
9745 if (_t.hoverState == 'out') {
9751 show : function (on_el)
9754 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9757 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
9758 if (this.html !== false) {
9759 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
9761 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
9762 if (!this.title.length) {
9763 this.el.select('.popover-title',true).hide();
9766 var placement = typeof this.placement == 'function' ?
9767 this.placement.call(this, this.el, on_el) :
9770 var autoToken = /\s?auto?\s?/i;
9771 var autoPlace = autoToken.test(placement);
9773 placement = placement.replace(autoToken, '') || 'top';
9777 //this.el.setXY([0,0]);
9779 this.el.dom.style.display='block';
9780 this.el.addClass(placement);
9782 //this.el.appendTo(on_el);
9784 var p = this.getPosition();
9785 var box = this.el.getBox();
9790 var align = Roo.bootstrap.Popover.alignment[placement]
9791 this.el.alignTo(on_el, align[0],align[1]);
9792 //var arrow = this.el.select('.arrow',true).first();
9793 //arrow.set(align[2],
9795 this.el.addClass('in');
9796 this.hoverState = null;
9798 if (this.el.hasClass('fade')) {
9805 this.el.setXY([0,0]);
9806 this.el.removeClass('in');
9813 Roo.bootstrap.Popover.alignment = {
9814 'left' : ['r-l', [-10,0], 'right'],
9815 'right' : ['l-r', [10,0], 'left'],
9816 'bottom' : ['t-b', [0,10], 'top'],
9817 'top' : [ 'b-t', [0,-10], 'bottom']
9828 * @class Roo.bootstrap.Progress
9829 * @extends Roo.bootstrap.Component
9830 * Bootstrap Progress class
9831 * @cfg {Boolean} striped striped of the progress bar
9832 * @cfg {Boolean} active animated of the progress bar
9836 * Create a new Progress
9837 * @param {Object} config The config object
9840 Roo.bootstrap.Progress = function(config){
9841 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
9844 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
9849 getAutoCreate : function(){
9857 cfg.cls += ' progress-striped';
9861 cfg.cls += ' active';
9880 * @class Roo.bootstrap.ProgressBar
9881 * @extends Roo.bootstrap.Component
9882 * Bootstrap ProgressBar class
9883 * @cfg {Number} aria_valuenow aria-value now
9884 * @cfg {Number} aria_valuemin aria-value min
9885 * @cfg {Number} aria_valuemax aria-value max
9886 * @cfg {String} label label for the progress bar
9887 * @cfg {String} panel (success | info | warning | danger )
9888 * @cfg {String} role role of the progress bar
9889 * @cfg {String} sr_only text
9893 * Create a new ProgressBar
9894 * @param {Object} config The config object
9897 Roo.bootstrap.ProgressBar = function(config){
9898 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
9901 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
9905 aria_valuemax : 100,
9911 getAutoCreate : function()
9916 cls: 'progress-bar',
9917 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
9929 cfg.role = this.role;
9932 if(this.aria_valuenow){
9933 cfg['aria-valuenow'] = this.aria_valuenow;
9936 if(this.aria_valuemin){
9937 cfg['aria-valuemin'] = this.aria_valuemin;
9940 if(this.aria_valuemax){
9941 cfg['aria-valuemax'] = this.aria_valuemax;
9944 if(this.label && !this.sr_only){
9945 cfg.html = this.label;
9949 cfg.cls += ' progress-bar-' + this.panel;
9955 update : function(aria_valuenow)
9957 this.aria_valuenow = aria_valuenow;
9959 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
9974 * @class Roo.bootstrap.TabPanel
9975 * @extends Roo.bootstrap.Component
9976 * Bootstrap TabPanel class
9977 * @cfg {Boolean} active panel active
9978 * @cfg {String} html panel content
9979 * @cfg {String} tabId tab relate id
9983 * Create a new TabPanel
9984 * @param {Object} config The config object
9987 Roo.bootstrap.TabPanel = function(config){
9988 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
9991 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
9997 getAutoCreate : function(){
10001 html: this.html || ''
10005 cfg.cls += ' active';
10009 cfg.tabId = this.tabId;
10027 * @class Roo.bootstrap.DateField
10028 * @extends Roo.bootstrap.Input
10029 * Bootstrap DateField class
10030 * @cfg {Number} weekStart default 0
10031 * @cfg {Number} weekStart default 0
10032 * @cfg {Number} viewMode default empty, (months|years)
10033 * @cfg {Number} minViewMode default empty, (months|years)
10034 * @cfg {Number} startDate default -Infinity
10035 * @cfg {Number} endDate default Infinity
10036 * @cfg {Boolean} todayHighlight default false
10037 * @cfg {Boolean} todayBtn default false
10038 * @cfg {Boolean} calendarWeeks default false
10039 * @cfg {Object} daysOfWeekDisabled default empty
10041 * @cfg {Boolean} keyboardNavigation default true
10042 * @cfg {String} language default en
10045 * Create a new DateField
10046 * @param {Object} config The config object
10049 Roo.bootstrap.DateField = function(config){
10050 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
10053 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
10056 * @cfg {String} format
10057 * The default date format string which can be overriden for localization support. The format must be
10058 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10062 * @cfg {String} altFormats
10063 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
10064 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
10066 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
10074 todayHighlight : false,
10080 keyboardNavigation: true,
10082 calendarWeeks: false,
10084 startDate: -Infinity,
10088 daysOfWeekDisabled: [],
10092 UTCDate: function()
10094 return new Date(Date.UTC.apply(Date, arguments));
10097 UTCToday: function()
10099 var today = new Date();
10100 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
10103 getDate: function() {
10104 var d = this.getUTCDate();
10105 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
10108 getUTCDate: function() {
10112 setDate: function(d) {
10113 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
10116 setUTCDate: function(d) {
10118 this.setValue(this.formatDate(this.date));
10121 onRender: function(ct, position)
10124 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
10126 this.language = this.language || 'en';
10127 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
10128 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
10130 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
10131 this.format = this.format || 'm/d/y';
10132 this.isInline = false;
10133 this.isInput = true;
10134 this.component = this.el.select('.add-on', true).first() || false;
10135 this.component = (this.component && this.component.length === 0) ? false : this.component;
10136 this.hasInput = this.component && this.inputEL().length;
10138 if (typeof(this.minViewMode === 'string')) {
10139 switch (this.minViewMode) {
10141 this.minViewMode = 1;
10144 this.minViewMode = 2;
10147 this.minViewMode = 0;
10152 if (typeof(this.viewMode === 'string')) {
10153 switch (this.viewMode) {
10166 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
10168 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10170 this.picker().on('mousedown', this.onMousedown, this);
10171 this.picker().on('click', this.onClick, this);
10173 this.picker().addClass('datepicker-dropdown');
10175 this.startViewMode = this.viewMode;
10178 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
10179 if(!this.calendarWeeks){
10184 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
10185 v.attr('colspan', function(i, val){
10186 return parseInt(val) + 1;
10191 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
10193 this.setStartDate(this.startDate);
10194 this.setEndDate(this.endDate);
10196 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
10203 if(this.isInline) {
10208 picker : function()
10210 return this.el.select('.datepicker', true).first();
10213 fillDow: function()
10215 var dowCnt = this.weekStart;
10224 if(this.calendarWeeks){
10232 while (dowCnt < this.weekStart + 7) {
10236 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
10240 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
10243 fillMonths: function()
10246 var months = this.picker().select('>.datepicker-months td', true).first();
10248 months.dom.innerHTML = '';
10254 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
10257 months.createChild(month);
10262 update: function(){
10264 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
10266 if (this.date < this.startDate) {
10267 this.viewDate = new Date(this.startDate);
10268 } else if (this.date > this.endDate) {
10269 this.viewDate = new Date(this.endDate);
10271 this.viewDate = new Date(this.date);
10278 var d = new Date(this.viewDate),
10279 year = d.getUTCFullYear(),
10280 month = d.getUTCMonth(),
10281 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
10282 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
10283 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
10284 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
10285 currentDate = this.date && this.date.valueOf(),
10286 today = this.UTCToday();
10288 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
10290 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
10292 // this.picker.select('>tfoot th.today').
10293 // .text(dates[this.language].today)
10294 // .toggle(this.todayBtn !== false);
10296 this.updateNavArrows();
10299 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
10301 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
10303 prevMonth.setUTCDate(day);
10305 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
10307 var nextMonth = new Date(prevMonth);
10309 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
10311 nextMonth = nextMonth.valueOf();
10313 var fillMonths = false;
10315 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
10317 while(prevMonth.valueOf() < nextMonth) {
10320 if (prevMonth.getUTCDay() === this.weekStart) {
10322 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
10330 if(this.calendarWeeks){
10331 // ISO 8601: First week contains first thursday.
10332 // ISO also states week starts on Monday, but we can be more abstract here.
10334 // Start of current week: based on weekstart/current date
10335 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
10336 // Thursday of this week
10337 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
10338 // First Thursday of year, year from thursday
10339 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
10340 // Calendar week: ms between thursdays, div ms per day, div 7 days
10341 calWeek = (th - yth) / 864e5 / 7 + 1;
10343 fillMonths.cn.push({
10351 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
10353 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
10356 if (this.todayHighlight &&
10357 prevMonth.getUTCFullYear() == today.getFullYear() &&
10358 prevMonth.getUTCMonth() == today.getMonth() &&
10359 prevMonth.getUTCDate() == today.getDate()) {
10360 clsName += ' today';
10363 if (currentDate && prevMonth.valueOf() === currentDate) {
10364 clsName += ' active';
10367 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
10368 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
10369 clsName += ' disabled';
10372 fillMonths.cn.push({
10374 cls: 'day ' + clsName,
10375 html: prevMonth.getDate()
10378 prevMonth.setDate(prevMonth.getDate()+1);
10381 var currentYear = this.date && this.date.getUTCFullYear();
10382 var currentMonth = this.date && this.date.getUTCMonth();
10384 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
10386 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
10387 v.removeClass('active');
10389 if(currentYear === year && k === currentMonth){
10390 v.addClass('active');
10393 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
10394 v.addClass('disabled');
10400 year = parseInt(year/10, 10) * 10;
10402 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
10404 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
10407 for (var i = -1; i < 11; i++) {
10408 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
10410 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
10418 showMode: function(dir) {
10420 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
10422 Roo.each(this.picker().select('>div',true).elements, function(v){
10423 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10426 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
10431 if(this.isInline) return;
10433 this.picker().removeClass(['bottom', 'top']);
10435 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
10437 * place to the top of element!
10441 this.picker().addClass('top');
10442 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10447 this.picker().addClass('bottom');
10449 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10452 parseDate : function(value){
10453 if(!value || value instanceof Date){
10456 var v = Date.parseDate(value, this.format);
10457 if (!v && this.useIso) {
10458 v = Date.parseDate(value, 'Y-m-d');
10460 if(!v && this.altFormats){
10461 if(!this.altFormatsArray){
10462 this.altFormatsArray = this.altFormats.split("|");
10464 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
10465 v = Date.parseDate(value, this.altFormatsArray[i]);
10471 formatDate : function(date, fmt){
10472 return (!date || !(date instanceof Date)) ?
10473 date : date.dateFormat(fmt || this.format);
10476 onFocus : function()
10478 Roo.bootstrap.DateField.superclass.onFocus.call(this);
10482 onBlur : function()
10484 Roo.bootstrap.DateField.superclass.onBlur.call(this);
10490 this.picker().show();
10497 if(this.isInline) return;
10498 this.picker().hide();
10499 this.viewMode = this.startViewMode;
10504 onMousedown: function(e){
10505 e.stopPropagation();
10506 e.preventDefault();
10509 keyup: function(e){
10510 Roo.bootstrap.DateField.superclass.keyup.call(this);
10515 fireKey: function(e){
10516 if (!this.picker().isVisible()){
10517 if (e.keyCode == 27) // allow escape to hide and re-show picker
10521 var dateChanged = false,
10523 newDate, newViewDate;
10527 e.preventDefault();
10531 if (!this.keyboardNavigation) break;
10532 dir = e.keyCode == 37 ? -1 : 1;
10535 newDate = this.moveYear(this.date, dir);
10536 newViewDate = this.moveYear(this.viewDate, dir);
10537 } else if (e.shiftKey){
10538 newDate = this.moveMonth(this.date, dir);
10539 newViewDate = this.moveMonth(this.viewDate, dir);
10541 newDate = new Date(this.date);
10542 newDate.setUTCDate(this.date.getUTCDate() + dir);
10543 newViewDate = new Date(this.viewDate);
10544 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
10546 if (this.dateWithinRange(newDate)){
10547 this.date = newDate;
10548 this.viewDate = newViewDate;
10549 this.setValue(this.formatDate(this.date));
10551 e.preventDefault();
10552 dateChanged = true;
10557 if (!this.keyboardNavigation) break;
10558 dir = e.keyCode == 38 ? -1 : 1;
10560 newDate = this.moveYear(this.date, dir);
10561 newViewDate = this.moveYear(this.viewDate, dir);
10562 } else if (e.shiftKey){
10563 newDate = this.moveMonth(this.date, dir);
10564 newViewDate = this.moveMonth(this.viewDate, dir);
10566 newDate = new Date(this.date);
10567 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
10568 newViewDate = new Date(this.viewDate);
10569 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
10571 if (this.dateWithinRange(newDate)){
10572 this.date = newDate;
10573 this.viewDate = newViewDate;
10574 this.setValue(this.formatDate(this.date));
10576 e.preventDefault();
10577 dateChanged = true;
10581 this.setValue(this.formatDate(this.date));
10583 e.preventDefault();
10586 this.setValue(this.formatDate(this.date));
10593 onClick: function(e) {
10594 e.stopPropagation();
10595 e.preventDefault();
10597 var target = e.getTarget();
10599 if(target.nodeName.toLowerCase() === 'i'){
10600 target = Roo.get(target).dom.parentNode;
10603 var nodeName = target.nodeName;
10604 var className = target.className;
10605 var html = target.innerHTML;
10607 switch(nodeName.toLowerCase()) {
10609 switch(className) {
10615 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
10616 switch(this.viewMode){
10618 this.viewDate = this.moveMonth(this.viewDate, dir);
10622 this.viewDate = this.moveYear(this.viewDate, dir);
10628 var date = new Date();
10629 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
10631 this.setValue(this.formatDate(this.date));
10637 if (className.indexOf('disabled') === -1) {
10638 this.viewDate.setUTCDate(1);
10639 if (className.indexOf('month') !== -1) {
10640 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
10642 var year = parseInt(html, 10) || 0;
10643 this.viewDate.setUTCFullYear(year);
10652 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
10653 var day = parseInt(html, 10) || 1;
10654 var year = this.viewDate.getUTCFullYear(),
10655 month = this.viewDate.getUTCMonth();
10657 if (className.indexOf('old') !== -1) {
10664 } else if (className.indexOf('new') !== -1) {
10672 this.date = this.UTCDate(year, month, day,0,0,0,0);
10673 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
10675 this.setValue(this.formatDate(this.date));
10682 setStartDate: function(startDate){
10683 this.startDate = startDate || -Infinity;
10684 if (this.startDate !== -Infinity) {
10685 this.startDate = this.parseDate(this.startDate);
10688 this.updateNavArrows();
10691 setEndDate: function(endDate){
10692 this.endDate = endDate || Infinity;
10693 if (this.endDate !== Infinity) {
10694 this.endDate = this.parseDate(this.endDate);
10697 this.updateNavArrows();
10700 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
10701 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
10702 if (typeof(this.daysOfWeekDisabled) !== 'object') {
10703 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
10705 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
10706 return parseInt(d, 10);
10709 this.updateNavArrows();
10712 updateNavArrows: function() {
10713 var d = new Date(this.viewDate),
10714 year = d.getUTCFullYear(),
10715 month = d.getUTCMonth();
10717 Roo.each(this.picker().select('.prev', true).elements, function(v){
10719 switch (this.viewMode) {
10722 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
10728 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
10735 Roo.each(this.picker().select('.next', true).elements, function(v){
10737 switch (this.viewMode) {
10740 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
10746 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
10754 moveMonth: function(date, dir){
10755 if (!dir) return date;
10756 var new_date = new Date(date.valueOf()),
10757 day = new_date.getUTCDate(),
10758 month = new_date.getUTCMonth(),
10759 mag = Math.abs(dir),
10761 dir = dir > 0 ? 1 : -1;
10764 // If going back one month, make sure month is not current month
10765 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
10767 return new_date.getUTCMonth() == month;
10769 // If going forward one month, make sure month is as expected
10770 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
10772 return new_date.getUTCMonth() != new_month;
10774 new_month = month + dir;
10775 new_date.setUTCMonth(new_month);
10776 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
10777 if (new_month < 0 || new_month > 11)
10778 new_month = (new_month + 12) % 12;
10780 // For magnitudes >1, move one month at a time...
10781 for (var i=0; i<mag; i++)
10782 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
10783 new_date = this.moveMonth(new_date, dir);
10784 // ...then reset the day, keeping it in the new month
10785 new_month = new_date.getUTCMonth();
10786 new_date.setUTCDate(day);
10788 return new_month != new_date.getUTCMonth();
10791 // Common date-resetting loop -- if date is beyond end of month, make it
10794 new_date.setUTCDate(--day);
10795 new_date.setUTCMonth(new_month);
10800 moveYear: function(date, dir){
10801 return this.moveMonth(date, dir*12);
10804 dateWithinRange: function(date){
10805 return date >= this.startDate && date <= this.endDate;
10809 remove: function() {
10810 this.picker().remove();
10815 Roo.apply(Roo.bootstrap.DateField, {
10826 html: '<i class="icon-arrow-left"/>'
10836 html: '<i class="icon-arrow-right"/>'
10878 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
10879 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
10880 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
10881 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
10882 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
10895 navFnc: 'FullYear',
10900 navFnc: 'FullYear',
10905 Roo.apply(Roo.bootstrap.DateField, {
10909 cls: 'datepicker dropdown-menu',
10913 cls: 'datepicker-days',
10917 cls: 'table-condensed',
10919 Roo.bootstrap.DateField.head,
10923 Roo.bootstrap.DateField.footer
10930 cls: 'datepicker-months',
10934 cls: 'table-condensed',
10936 Roo.bootstrap.DateField.head,
10937 Roo.bootstrap.DateField.content,
10938 Roo.bootstrap.DateField.footer
10945 cls: 'datepicker-years',
10949 cls: 'table-condensed',
10951 Roo.bootstrap.DateField.head,
10952 Roo.bootstrap.DateField.content,
10953 Roo.bootstrap.DateField.footer
10972 * @class Roo.bootstrap.CheckBox
10973 * @extends Roo.bootstrap.Input
10974 * Bootstrap CheckBox class
10976 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
10977 * @cfg {String} boxLabel The text that appears beside the checkbox
10978 * @cfg {Boolean} checked initnal the element
10981 * Create a new CheckBox
10982 * @param {Object} config The config object
10985 Roo.bootstrap.CheckBox = function(config){
10986 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
10991 * Fires when the element is checked or unchecked.
10992 * @param {Roo.bootstrap.CheckBox} this This input
10993 * @param {Boolean} checked The new checked value
10999 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
11001 inputType: 'checkbox',
11007 getAutoCreate : function()
11009 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11015 cfg.cls = 'form-group' //input-group
11020 type : this.inputType,
11021 value : (!this.checked) ? this.valueOff : this.value,
11023 placeholder : this.placeholder || ''
11027 if (this.disabled) {
11028 input.disabled=true;
11032 input.checked = this.checked;
11036 input.name = this.name;
11040 input.cls += ' input-' + this.size;
11044 ['xs','sm','md','lg'].map(function(size){
11045 if (settings[size]) {
11046 cfg.cls += ' col-' + size + '-' + settings[size];
11050 var inputblock = input;
11052 if (this.before || this.after) {
11055 cls : 'input-group',
11059 inputblock.cn.push({
11061 cls : 'input-group-addon',
11065 inputblock.cn.push(input);
11067 inputblock.cn.push({
11069 cls : 'input-group-addon',
11076 if (align ==='left' && this.fieldLabel.length) {
11077 Roo.log("left and has label");
11083 cls : 'control-label col-md-' + this.labelWidth,
11084 html : this.fieldLabel
11088 cls : "col-md-" + (12 - this.labelWidth),
11095 } else if ( this.fieldLabel.length) {
11102 cls: 'control-label box-input-label',
11103 //cls : 'input-group-addon',
11104 html : this.fieldLabel
11114 Roo.log(" no label && no align");
11129 html: this.boxLabel
11138 * return the real input element.
11140 inputEl: function ()
11142 return this.el.select('input.form-box',true).first();
11145 initEvents : function()
11147 Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
11149 this.inputEl().on('click', this.onClick, this);
11153 onClick : function()
11155 this.setChecked(!this.checked);
11158 setChecked : function(state,suppressEvent)
11160 this.checked = state;
11162 if(suppressEvent !== true){
11163 this.fireEvent('check', this, state);
11166 this.inputEl().dom.value = state ? this.value : this.valueOff;
11180 * @class Roo.bootstrap.Radio
11181 * @extends Roo.bootstrap.CheckBox
11182 * Bootstrap Radio class
11185 * Create a new Radio
11186 * @param {Object} config The config object
11189 Roo.bootstrap.Radio = function(config){
11190 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
11194 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
11196 inputType: 'radio',
11198 getAutoCreate : function()
11200 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11206 cfg.cls = 'form-group' //input-group
11211 type : this.inputType,
11212 value : (!this.checked) ? this.valueOff : this.value,
11214 placeholder : this.placeholder || ''
11218 if (this.disabled) {
11219 input.disabled=true;
11223 input.checked = this.checked;
11227 input.name = this.name;
11231 input.cls += ' input-' + this.size;
11235 ['xs','sm','md','lg'].map(function(size){
11236 if (settings[size]) {
11237 cfg.cls += ' col-' + size + '-' + settings[size];
11241 var inputblock = input;
11243 if (this.before || this.after) {
11246 cls : 'input-group',
11250 inputblock.cn.push({
11252 cls : 'input-group-addon',
11256 inputblock.cn.push(input);
11258 inputblock.cn.push({
11260 cls : 'input-group-addon',
11267 if (align ==='left' && this.fieldLabel.length) {
11268 Roo.log("left and has label");
11274 cls : 'control-label col-md-' + this.labelWidth,
11275 html : this.fieldLabel
11279 cls : "col-md-" + (12 - this.labelWidth),
11286 } else if ( this.fieldLabel.length) {
11293 cls: 'control-label box-input-label',
11294 //cls : 'input-group-addon',
11295 html : this.fieldLabel
11305 Roo.log(" no label && no align");
11320 html: this.boxLabel
11328 onClick : function()
11330 this.setChecked(true);
11333 setChecked : function(state,suppressEvent)
11335 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
11339 this.checked = state;
11341 if(suppressEvent !== true){
11342 this.fireEvent('check', this, state);
11345 this.inputEl().dom.value = state ? this.value : this.valueOff;
11349 getGroupValue : function()
11351 if(typeof(this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true)) == 'undefined'){
11355 return this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true).value;
11359 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
11360 * @return {Mixed} value The field value
11362 getValue : function(){
11363 return this.getGroupValue();
11377 * @class Roo.bootstrap.HtmlEditor
11378 * @extends Roo.bootstrap.Component
11379 * Bootstrap HtmlEditor class
11382 * Create a new HtmlEditor
11383 * @param {Object} config The config object
11386 Roo.bootstrap.HtmlEditor = function(config){
11387 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
11392 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.Component, {
11394 getAutoCreate : function()
11398 // var toolbar = new Roo.bootstrap.ButtonGroup({
11402 // new Roo.bootstrap.Button({
11415 * @class Roo.bootstrap.Table.AbstractSelectionModel
11416 * @extends Roo.util.Observable
11417 * Abstract base class for grid SelectionModels. It provides the interface that should be
11418 * implemented by descendant classes. This class should not be directly instantiated.
11421 Roo.bootstrap.Table.AbstractSelectionModel = function(){
11422 this.locked = false;
11423 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
11427 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
11428 /** @ignore Called by the grid automatically. Do not call directly. */
11429 init : function(grid){
11435 * Locks the selections.
11438 this.locked = true;
11442 * Unlocks the selections.
11444 unlock : function(){
11445 this.locked = false;
11449 * Returns true if the selections are locked.
11450 * @return {Boolean}
11452 isLocked : function(){
11453 return this.locked;
11457 * @class Roo.bootstrap.Table.ColumnModel
11458 * @extends Roo.util.Observable
11459 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
11460 * the columns in the table.
11463 * @param {Object} config An Array of column config objects. See this class's
11464 * config objects for details.
11466 Roo.bootstrap.Table.ColumnModel = function(config){
11468 * The config passed into the constructor
11470 this.config = config;
11473 // if no id, create one
11474 // if the column does not have a dataIndex mapping,
11475 // map it to the order it is in the config
11476 for(var i = 0, len = config.length; i < len; i++){
11478 if(typeof c.dataIndex == "undefined"){
11481 if(typeof c.renderer == "string"){
11482 c.renderer = Roo.util.Format[c.renderer];
11484 if(typeof c.id == "undefined"){
11487 // if(c.editor && c.editor.xtype){
11488 // c.editor = Roo.factory(c.editor, Roo.grid);
11490 // if(c.editor && c.editor.isFormField){
11491 // c.editor = new Roo.grid.GridEditor(c.editor);
11494 this.lookup[c.id] = c;
11498 * The width of columns which have no width specified (defaults to 100)
11501 this.defaultWidth = 100;
11504 * Default sortable of columns which have no sortable specified (defaults to false)
11507 this.defaultSortable = false;
11511 * @event widthchange
11512 * Fires when the width of a column changes.
11513 * @param {ColumnModel} this
11514 * @param {Number} columnIndex The column index
11515 * @param {Number} newWidth The new width
11517 "widthchange": true,
11519 * @event headerchange
11520 * Fires when the text of a header changes.
11521 * @param {ColumnModel} this
11522 * @param {Number} columnIndex The column index
11523 * @param {Number} newText The new header text
11525 "headerchange": true,
11527 * @event hiddenchange
11528 * Fires when a column is hidden or "unhidden".
11529 * @param {ColumnModel} this
11530 * @param {Number} columnIndex The column index
11531 * @param {Boolean} hidden true if hidden, false otherwise
11533 "hiddenchange": true,
11535 * @event columnmoved
11536 * Fires when a column is moved.
11537 * @param {ColumnModel} this
11538 * @param {Number} oldIndex
11539 * @param {Number} newIndex
11541 "columnmoved" : true,
11543 * @event columlockchange
11544 * Fires when a column's locked state is changed
11545 * @param {ColumnModel} this
11546 * @param {Number} colIndex
11547 * @param {Boolean} locked true if locked
11549 "columnlockchange" : true
11551 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
11553 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
11555 * @cfg {String} header The header text to display in the Grid view.
11558 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
11559 * {@link Roo.data.Record} definition from which to draw the column's value. If not
11560 * specified, the column's index is used as an index into the Record's data Array.
11563 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
11564 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
11567 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
11568 * Defaults to the value of the {@link #defaultSortable} property.
11569 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
11572 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
11575 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
11578 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
11581 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
11584 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
11585 * given the cell's data value. See {@link #setRenderer}. If not specified, the
11586 * default renderer uses the raw data value.
11589 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
11593 * Returns the id of the column at the specified index.
11594 * @param {Number} index The column index
11595 * @return {String} the id
11597 getColumnId : function(index){
11598 return this.config[index].id;
11602 * Returns the column for a specified id.
11603 * @param {String} id The column id
11604 * @return {Object} the column
11606 getColumnById : function(id){
11607 return this.lookup[id];
11612 * Returns the column for a specified dataIndex.
11613 * @param {String} dataIndex The column dataIndex
11614 * @return {Object|Boolean} the column or false if not found
11616 getColumnByDataIndex: function(dataIndex){
11617 var index = this.findColumnIndex(dataIndex);
11618 return index > -1 ? this.config[index] : false;
11622 * Returns the index for a specified column id.
11623 * @param {String} id The column id
11624 * @return {Number} the index, or -1 if not found
11626 getIndexById : function(id){
11627 for(var i = 0, len = this.config.length; i < len; i++){
11628 if(this.config[i].id == id){
11636 * Returns the index for a specified column dataIndex.
11637 * @param {String} dataIndex The column dataIndex
11638 * @return {Number} the index, or -1 if not found
11641 findColumnIndex : function(dataIndex){
11642 for(var i = 0, len = this.config.length; i < len; i++){
11643 if(this.config[i].dataIndex == dataIndex){
11651 moveColumn : function(oldIndex, newIndex){
11652 var c = this.config[oldIndex];
11653 this.config.splice(oldIndex, 1);
11654 this.config.splice(newIndex, 0, c);
11655 this.dataMap = null;
11656 this.fireEvent("columnmoved", this, oldIndex, newIndex);
11659 isLocked : function(colIndex){
11660 return this.config[colIndex].locked === true;
11663 setLocked : function(colIndex, value, suppressEvent){
11664 if(this.isLocked(colIndex) == value){
11667 this.config[colIndex].locked = value;
11668 if(!suppressEvent){
11669 this.fireEvent("columnlockchange", this, colIndex, value);
11673 getTotalLockedWidth : function(){
11674 var totalWidth = 0;
11675 for(var i = 0; i < this.config.length; i++){
11676 if(this.isLocked(i) && !this.isHidden(i)){
11677 this.totalWidth += this.getColumnWidth(i);
11683 getLockedCount : function(){
11684 for(var i = 0, len = this.config.length; i < len; i++){
11685 if(!this.isLocked(i)){
11692 * Returns the number of columns.
11695 getColumnCount : function(visibleOnly){
11696 if(visibleOnly === true){
11698 for(var i = 0, len = this.config.length; i < len; i++){
11699 if(!this.isHidden(i)){
11705 return this.config.length;
11709 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
11710 * @param {Function} fn
11711 * @param {Object} scope (optional)
11712 * @return {Array} result
11714 getColumnsBy : function(fn, scope){
11716 for(var i = 0, len = this.config.length; i < len; i++){
11717 var c = this.config[i];
11718 if(fn.call(scope||this, c, i) === true){
11726 * Returns true if the specified column is sortable.
11727 * @param {Number} col The column index
11728 * @return {Boolean}
11730 isSortable : function(col){
11731 if(typeof this.config[col].sortable == "undefined"){
11732 return this.defaultSortable;
11734 return this.config[col].sortable;
11738 * Returns the rendering (formatting) function defined for the column.
11739 * @param {Number} col The column index.
11740 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
11742 getRenderer : function(col){
11743 if(!this.config[col].renderer){
11744 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
11746 return this.config[col].renderer;
11750 * Sets the rendering (formatting) function for a column.
11751 * @param {Number} col The column index
11752 * @param {Function} fn The function to use to process the cell's raw data
11753 * to return HTML markup for the grid view. The render function is called with
11754 * the following parameters:<ul>
11755 * <li>Data value.</li>
11756 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
11757 * <li>css A CSS style string to apply to the table cell.</li>
11758 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
11759 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
11760 * <li>Row index</li>
11761 * <li>Column index</li>
11762 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
11764 setRenderer : function(col, fn){
11765 this.config[col].renderer = fn;
11769 * Returns the width for the specified column.
11770 * @param {Number} col The column index
11773 getColumnWidth : function(col){
11774 return this.config[col].width * 1 || this.defaultWidth;
11778 * Sets the width for a column.
11779 * @param {Number} col The column index
11780 * @param {Number} width The new width
11782 setColumnWidth : function(col, width, suppressEvent){
11783 this.config[col].width = width;
11784 this.totalWidth = null;
11785 if(!suppressEvent){
11786 this.fireEvent("widthchange", this, col, width);
11791 * Returns the total width of all columns.
11792 * @param {Boolean} includeHidden True to include hidden column widths
11795 getTotalWidth : function(includeHidden){
11796 if(!this.totalWidth){
11797 this.totalWidth = 0;
11798 for(var i = 0, len = this.config.length; i < len; i++){
11799 if(includeHidden || !this.isHidden(i)){
11800 this.totalWidth += this.getColumnWidth(i);
11804 return this.totalWidth;
11808 * Returns the header for the specified column.
11809 * @param {Number} col The column index
11812 getColumnHeader : function(col){
11813 return this.config[col].header;
11817 * Sets the header for a column.
11818 * @param {Number} col The column index
11819 * @param {String} header The new header
11821 setColumnHeader : function(col, header){
11822 this.config[col].header = header;
11823 this.fireEvent("headerchange", this, col, header);
11827 * Returns the tooltip for the specified column.
11828 * @param {Number} col The column index
11831 getColumnTooltip : function(col){
11832 return this.config[col].tooltip;
11835 * Sets the tooltip for a column.
11836 * @param {Number} col The column index
11837 * @param {String} tooltip The new tooltip
11839 setColumnTooltip : function(col, tooltip){
11840 this.config[col].tooltip = tooltip;
11844 * Returns the dataIndex for the specified column.
11845 * @param {Number} col The column index
11848 getDataIndex : function(col){
11849 return this.config[col].dataIndex;
11853 * Sets the dataIndex for a column.
11854 * @param {Number} col The column index
11855 * @param {Number} dataIndex The new dataIndex
11857 setDataIndex : function(col, dataIndex){
11858 this.config[col].dataIndex = dataIndex;
11864 * Returns true if the cell is editable.
11865 * @param {Number} colIndex The column index
11866 * @param {Number} rowIndex The row index
11867 * @return {Boolean}
11869 isCellEditable : function(colIndex, rowIndex){
11870 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
11874 * Returns the editor defined for the cell/column.
11875 * return false or null to disable editing.
11876 * @param {Number} colIndex The column index
11877 * @param {Number} rowIndex The row index
11880 getCellEditor : function(colIndex, rowIndex){
11881 return this.config[colIndex].editor;
11885 * Sets if a column is editable.
11886 * @param {Number} col The column index
11887 * @param {Boolean} editable True if the column is editable
11889 setEditable : function(col, editable){
11890 this.config[col].editable = editable;
11895 * Returns true if the column is hidden.
11896 * @param {Number} colIndex The column index
11897 * @return {Boolean}
11899 isHidden : function(colIndex){
11900 return this.config[colIndex].hidden;
11905 * Returns true if the column width cannot be changed
11907 isFixed : function(colIndex){
11908 return this.config[colIndex].fixed;
11912 * Returns true if the column can be resized
11913 * @return {Boolean}
11915 isResizable : function(colIndex){
11916 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
11919 * Sets if a column is hidden.
11920 * @param {Number} colIndex The column index
11921 * @param {Boolean} hidden True if the column is hidden
11923 setHidden : function(colIndex, hidden){
11924 this.config[colIndex].hidden = hidden;
11925 this.totalWidth = null;
11926 this.fireEvent("hiddenchange", this, colIndex, hidden);
11930 * Sets the editor for a column.
11931 * @param {Number} col The column index
11932 * @param {Object} editor The editor object
11934 setEditor : function(col, editor){
11935 this.config[col].editor = editor;
11939 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
11940 if(typeof value == "string" && value.length < 1){
11946 // Alias for backwards compatibility
11947 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
11950 * @extends Roo.bootstrap.Table.AbstractSelectionModel
11951 * @class Roo.bootstrap.Table.RowSelectionModel
11952 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
11953 * It supports multiple selections and keyboard selection/navigation.
11955 * @param {Object} config
11958 Roo.bootstrap.Table.RowSelectionModel = function(config){
11959 Roo.apply(this, config);
11960 this.selections = new Roo.util.MixedCollection(false, function(o){
11965 this.lastActive = false;
11969 * @event selectionchange
11970 * Fires when the selection changes
11971 * @param {SelectionModel} this
11973 "selectionchange" : true,
11975 * @event afterselectionchange
11976 * Fires after the selection changes (eg. by key press or clicking)
11977 * @param {SelectionModel} this
11979 "afterselectionchange" : true,
11981 * @event beforerowselect
11982 * Fires when a row is selected being selected, return false to cancel.
11983 * @param {SelectionModel} this
11984 * @param {Number} rowIndex The selected index
11985 * @param {Boolean} keepExisting False if other selections will be cleared
11987 "beforerowselect" : true,
11990 * Fires when a row is selected.
11991 * @param {SelectionModel} this
11992 * @param {Number} rowIndex The selected index
11993 * @param {Roo.data.Record} r The record
11995 "rowselect" : true,
11997 * @event rowdeselect
11998 * Fires when a row is deselected.
11999 * @param {SelectionModel} this
12000 * @param {Number} rowIndex The selected index
12002 "rowdeselect" : true
12004 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
12005 this.locked = false;
12008 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
12010 * @cfg {Boolean} singleSelect
12011 * True to allow selection of only one row at a time (defaults to false)
12013 singleSelect : false,
12016 initEvents : function(){
12018 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
12019 this.grid.on("mousedown", this.handleMouseDown, this);
12020 }else{ // allow click to work like normal
12021 this.grid.on("rowclick", this.handleDragableRowClick, this);
12024 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
12025 "up" : function(e){
12027 this.selectPrevious(e.shiftKey);
12028 }else if(this.last !== false && this.lastActive !== false){
12029 var last = this.last;
12030 this.selectRange(this.last, this.lastActive-1);
12031 this.grid.getView().focusRow(this.lastActive);
12032 if(last !== false){
12036 this.selectFirstRow();
12038 this.fireEvent("afterselectionchange", this);
12040 "down" : function(e){
12042 this.selectNext(e.shiftKey);
12043 }else if(this.last !== false && this.lastActive !== false){
12044 var last = this.last;
12045 this.selectRange(this.last, this.lastActive+1);
12046 this.grid.getView().focusRow(this.lastActive);
12047 if(last !== false){
12051 this.selectFirstRow();
12053 this.fireEvent("afterselectionchange", this);
12058 var view = this.grid.view;
12059 view.on("refresh", this.onRefresh, this);
12060 view.on("rowupdated", this.onRowUpdated, this);
12061 view.on("rowremoved", this.onRemove, this);
12065 onRefresh : function(){
12066 var ds = this.grid.dataSource, i, v = this.grid.view;
12067 var s = this.selections;
12068 s.each(function(r){
12069 if((i = ds.indexOfId(r.id)) != -1){
12078 onRemove : function(v, index, r){
12079 this.selections.remove(r);
12083 onRowUpdated : function(v, index, r){
12084 if(this.isSelected(r)){
12085 v.onRowSelect(index);
12091 * @param {Array} records The records to select
12092 * @param {Boolean} keepExisting (optional) True to keep existing selections
12094 selectRecords : function(records, keepExisting){
12096 this.clearSelections();
12098 var ds = this.grid.dataSource;
12099 for(var i = 0, len = records.length; i < len; i++){
12100 this.selectRow(ds.indexOf(records[i]), true);
12105 * Gets the number of selected rows.
12108 getCount : function(){
12109 return this.selections.length;
12113 * Selects the first row in the grid.
12115 selectFirstRow : function(){
12120 * Select the last row.
12121 * @param {Boolean} keepExisting (optional) True to keep existing selections
12123 selectLastRow : function(keepExisting){
12124 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
12128 * Selects the row immediately following the last selected row.
12129 * @param {Boolean} keepExisting (optional) True to keep existing selections
12131 selectNext : function(keepExisting){
12132 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
12133 this.selectRow(this.last+1, keepExisting);
12134 this.grid.getView().focusRow(this.last);
12139 * Selects the row that precedes the last selected row.
12140 * @param {Boolean} keepExisting (optional) True to keep existing selections
12142 selectPrevious : function(keepExisting){
12144 this.selectRow(this.last-1, keepExisting);
12145 this.grid.getView().focusRow(this.last);
12150 * Returns the selected records
12151 * @return {Array} Array of selected records
12153 getSelections : function(){
12154 return [].concat(this.selections.items);
12158 * Returns the first selected record.
12161 getSelected : function(){
12162 return this.selections.itemAt(0);
12167 * Clears all selections.
12169 clearSelections : function(fast){
12170 if(this.locked) return;
12172 var ds = this.grid.dataSource;
12173 var s = this.selections;
12174 s.each(function(r){
12175 this.deselectRow(ds.indexOfId(r.id));
12179 this.selections.clear();
12186 * Selects all rows.
12188 selectAll : function(){
12189 if(this.locked) return;
12190 this.selections.clear();
12191 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
12192 this.selectRow(i, true);
12197 * Returns True if there is a selection.
12198 * @return {Boolean}
12200 hasSelection : function(){
12201 return this.selections.length > 0;
12205 * Returns True if the specified row is selected.
12206 * @param {Number/Record} record The record or index of the record to check
12207 * @return {Boolean}
12209 isSelected : function(index){
12210 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
12211 return (r && this.selections.key(r.id) ? true : false);
12215 * Returns True if the specified record id is selected.
12216 * @param {String} id The id of record to check
12217 * @return {Boolean}
12219 isIdSelected : function(id){
12220 return (this.selections.key(id) ? true : false);
12224 handleMouseDown : function(e, t){
12225 var view = this.grid.getView(), rowIndex;
12226 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
12229 if(e.shiftKey && this.last !== false){
12230 var last = this.last;
12231 this.selectRange(last, rowIndex, e.ctrlKey);
12232 this.last = last; // reset the last
12233 view.focusRow(rowIndex);
12235 var isSelected = this.isSelected(rowIndex);
12236 if(e.button !== 0 && isSelected){
12237 view.focusRow(rowIndex);
12238 }else if(e.ctrlKey && isSelected){
12239 this.deselectRow(rowIndex);
12240 }else if(!isSelected){
12241 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
12242 view.focusRow(rowIndex);
12245 this.fireEvent("afterselectionchange", this);
12248 handleDragableRowClick : function(grid, rowIndex, e)
12250 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
12251 this.selectRow(rowIndex, false);
12252 grid.view.focusRow(rowIndex);
12253 this.fireEvent("afterselectionchange", this);
12258 * Selects multiple rows.
12259 * @param {Array} rows Array of the indexes of the row to select
12260 * @param {Boolean} keepExisting (optional) True to keep existing selections
12262 selectRows : function(rows, keepExisting){
12264 this.clearSelections();
12266 for(var i = 0, len = rows.length; i < len; i++){
12267 this.selectRow(rows[i], true);
12272 * Selects a range of rows. All rows in between startRow and endRow are also selected.
12273 * @param {Number} startRow The index of the first row in the range
12274 * @param {Number} endRow The index of the last row in the range
12275 * @param {Boolean} keepExisting (optional) True to retain existing selections
12277 selectRange : function(startRow, endRow, keepExisting){
12278 if(this.locked) return;
12280 this.clearSelections();
12282 if(startRow <= endRow){
12283 for(var i = startRow; i <= endRow; i++){
12284 this.selectRow(i, true);
12287 for(var i = startRow; i >= endRow; i--){
12288 this.selectRow(i, true);
12294 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
12295 * @param {Number} startRow The index of the first row in the range
12296 * @param {Number} endRow The index of the last row in the range
12298 deselectRange : function(startRow, endRow, preventViewNotify){
12299 if(this.locked) return;
12300 for(var i = startRow; i <= endRow; i++){
12301 this.deselectRow(i, preventViewNotify);
12307 * @param {Number} row The index of the row to select
12308 * @param {Boolean} keepExisting (optional) True to keep existing selections
12310 selectRow : function(index, keepExisting, preventViewNotify){
12311 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
12312 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
12313 if(!keepExisting || this.singleSelect){
12314 this.clearSelections();
12316 var r = this.grid.dataSource.getAt(index);
12317 this.selections.add(r);
12318 this.last = this.lastActive = index;
12319 if(!preventViewNotify){
12320 this.grid.getView().onRowSelect(index);
12322 this.fireEvent("rowselect", this, index, r);
12323 this.fireEvent("selectionchange", this);
12329 * @param {Number} row The index of the row to deselect
12331 deselectRow : function(index, preventViewNotify){
12332 if(this.locked) return;
12333 if(this.last == index){
12336 if(this.lastActive == index){
12337 this.lastActive = false;
12339 var r = this.grid.dataSource.getAt(index);
12340 this.selections.remove(r);
12341 if(!preventViewNotify){
12342 this.grid.getView().onRowDeselect(index);
12344 this.fireEvent("rowdeselect", this, index);
12345 this.fireEvent("selectionchange", this);
12349 restoreLast : function(){
12351 this.last = this._last;
12356 acceptsNav : function(row, col, cm){
12357 return !cm.isHidden(col) && cm.isCellEditable(col, row);
12361 onEditorKey : function(field, e){
12362 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
12367 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
12369 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
12371 }else if(k == e.ENTER && !e.ctrlKey){
12375 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
12377 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
12379 }else if(k == e.ESC){
12383 g.startEditing(newCell[0], newCell[1]);
12388 * Ext JS Library 1.1.1
12389 * Copyright(c) 2006-2007, Ext JS, LLC.
12391 * Originally Released Under LGPL - original licence link has changed is not relivant.
12394 * <script type="text/javascript">
12398 * @class Roo.Toolbar
12399 * Basic Toolbar class.
12401 * Creates a new Toolbar
12402 * @param {Object} container The config object
12404 Roo.Toolbar = function(container, buttons, config)
12406 /// old consturctor format still supported..
12407 if(container instanceof Array){ // omit the container for later rendering
12408 buttons = container;
12412 if (typeof(container) == 'object' && container.xtype) {
12413 config = container;
12414 container = config.container;
12415 buttons = config.buttons || []; // not really - use items!!
12418 if (config && config.items) {
12419 xitems = config.items;
12420 delete config.items;
12422 Roo.apply(this, config);
12423 this.buttons = buttons;
12426 this.render(container);
12428 this.xitems = xitems;
12429 Roo.each(xitems, function(b) {
12435 Roo.Toolbar.prototype = {
12437 * @cfg {Array} items
12438 * array of button configs or elements to add (will be converted to a MixedCollection)
12442 * @cfg {String/HTMLElement/Element} container
12443 * The id or element that will contain the toolbar
12446 render : function(ct){
12447 this.el = Roo.get(ct);
12449 this.el.addClass(this.cls);
12451 // using a table allows for vertical alignment
12452 // 100% width is needed by Safari...
12453 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12454 this.tr = this.el.child("tr", true);
12456 this.items = new Roo.util.MixedCollection(false, function(o){
12457 return o.id || ("item" + (++autoId));
12460 this.add.apply(this, this.buttons);
12461 delete this.buttons;
12466 * Adds element(s) to the toolbar -- this function takes a variable number of
12467 * arguments of mixed type and adds them to the toolbar.
12468 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12470 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12471 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12472 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12473 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12474 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12475 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12476 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12477 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12478 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12480 * @param {Mixed} arg2
12481 * @param {Mixed} etc.
12484 var a = arguments, l = a.length;
12485 for(var i = 0; i < l; i++){
12490 _add : function(el) {
12493 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12496 if (el.applyTo){ // some kind of form field
12497 return this.addField(el);
12499 if (el.render){ // some kind of Toolbar.Item
12500 return this.addItem(el);
12502 if (typeof el == "string"){ // string
12503 if(el == "separator" || el == "-"){
12504 return this.addSeparator();
12507 return this.addSpacer();
12510 return this.addFill();
12512 return this.addText(el);
12515 if(el.tagName){ // element
12516 return this.addElement(el);
12518 if(typeof el == "object"){ // must be button config?
12519 return this.addButton(el);
12521 // and now what?!?!
12527 * Add an Xtype element
12528 * @param {Object} xtype Xtype Object
12529 * @return {Object} created Object
12531 addxtype : function(e){
12532 return this.add(e);
12536 * Returns the Element for this toolbar.
12537 * @return {Roo.Element}
12539 getEl : function(){
12545 * @return {Roo.Toolbar.Item} The separator item
12547 addSeparator : function(){
12548 return this.addItem(new Roo.Toolbar.Separator());
12552 * Adds a spacer element
12553 * @return {Roo.Toolbar.Spacer} The spacer item
12555 addSpacer : function(){
12556 return this.addItem(new Roo.Toolbar.Spacer());
12560 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12561 * @return {Roo.Toolbar.Fill} The fill item
12563 addFill : function(){
12564 return this.addItem(new Roo.Toolbar.Fill());
12568 * Adds any standard HTML element to the toolbar
12569 * @param {String/HTMLElement/Element} el The element or id of the element to add
12570 * @return {Roo.Toolbar.Item} The element's item
12572 addElement : function(el){
12573 return this.addItem(new Roo.Toolbar.Item(el));
12576 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12577 * @type Roo.util.MixedCollection
12582 * Adds any Toolbar.Item or subclass
12583 * @param {Roo.Toolbar.Item} item
12584 * @return {Roo.Toolbar.Item} The item
12586 addItem : function(item){
12587 var td = this.nextBlock();
12589 this.items.add(item);
12594 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12595 * @param {Object/Array} config A button config or array of configs
12596 * @return {Roo.Toolbar.Button/Array}
12598 addButton : function(config){
12599 if(config instanceof Array){
12601 for(var i = 0, len = config.length; i < len; i++) {
12602 buttons.push(this.addButton(config[i]));
12607 if(!(config instanceof Roo.Toolbar.Button)){
12609 new Roo.Toolbar.SplitButton(config) :
12610 new Roo.Toolbar.Button(config);
12612 var td = this.nextBlock();
12619 * Adds text to the toolbar
12620 * @param {String} text The text to add
12621 * @return {Roo.Toolbar.Item} The element's item
12623 addText : function(text){
12624 return this.addItem(new Roo.Toolbar.TextItem(text));
12628 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12629 * @param {Number} index The index where the item is to be inserted
12630 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12631 * @return {Roo.Toolbar.Button/Item}
12633 insertButton : function(index, item){
12634 if(item instanceof Array){
12636 for(var i = 0, len = item.length; i < len; i++) {
12637 buttons.push(this.insertButton(index + i, item[i]));
12641 if (!(item instanceof Roo.Toolbar.Button)){
12642 item = new Roo.Toolbar.Button(item);
12644 var td = document.createElement("td");
12645 this.tr.insertBefore(td, this.tr.childNodes[index]);
12647 this.items.insert(index, item);
12652 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12653 * @param {Object} config
12654 * @return {Roo.Toolbar.Item} The element's item
12656 addDom : function(config, returnEl){
12657 var td = this.nextBlock();
12658 Roo.DomHelper.overwrite(td, config);
12659 var ti = new Roo.Toolbar.Item(td.firstChild);
12661 this.items.add(ti);
12666 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12667 * @type Roo.util.MixedCollection
12672 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
12673 * Note: the field should not have been rendered yet. For a field that has already been
12674 * rendered, use {@link #addElement}.
12675 * @param {Roo.form.Field} field
12676 * @return {Roo.ToolbarItem}
12680 addField : function(field) {
12681 if (!this.fields) {
12683 this.fields = new Roo.util.MixedCollection(false, function(o){
12684 return o.id || ("item" + (++autoId));
12689 var td = this.nextBlock();
12691 var ti = new Roo.Toolbar.Item(td.firstChild);
12693 this.items.add(ti);
12694 this.fields.add(field);
12705 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12706 this.el.child('div').hide();
12714 this.el.child('div').show();
12718 nextBlock : function(){
12719 var td = document.createElement("td");
12720 this.tr.appendChild(td);
12725 destroy : function(){
12726 if(this.items){ // rendered?
12727 Roo.destroy.apply(Roo, this.items.items);
12729 if(this.fields){ // rendered?
12730 Roo.destroy.apply(Roo, this.fields.items);
12732 Roo.Element.uncache(this.el, this.tr);
12737 * @class Roo.Toolbar.Item
12738 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12740 * Creates a new Item
12741 * @param {HTMLElement} el
12743 Roo.Toolbar.Item = function(el){
12744 this.el = Roo.getDom(el);
12745 this.id = Roo.id(this.el);
12746 this.hidden = false;
12749 Roo.Toolbar.Item.prototype = {
12752 * Get this item's HTML Element
12753 * @return {HTMLElement}
12755 getEl : function(){
12760 render : function(td){
12762 td.appendChild(this.el);
12766 * Removes and destroys this item.
12768 destroy : function(){
12769 this.td.parentNode.removeChild(this.td);
12776 this.hidden = false;
12777 this.td.style.display = "";
12784 this.hidden = true;
12785 this.td.style.display = "none";
12789 * Convenience function for boolean show/hide.
12790 * @param {Boolean} visible true to show/false to hide
12792 setVisible: function(visible){
12801 * Try to focus this item.
12803 focus : function(){
12804 Roo.fly(this.el).focus();
12808 * Disables this item.
12810 disable : function(){
12811 Roo.fly(this.td).addClass("x-item-disabled");
12812 this.disabled = true;
12813 this.el.disabled = true;
12817 * Enables this item.
12819 enable : function(){
12820 Roo.fly(this.td).removeClass("x-item-disabled");
12821 this.disabled = false;
12822 this.el.disabled = false;
12828 * @class Roo.Toolbar.Separator
12829 * @extends Roo.Toolbar.Item
12830 * A simple toolbar separator class
12832 * Creates a new Separator
12834 Roo.Toolbar.Separator = function(){
12835 var s = document.createElement("span");
12836 s.className = "ytb-sep";
12837 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12839 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12840 enable:Roo.emptyFn,
12841 disable:Roo.emptyFn,
12846 * @class Roo.Toolbar.Spacer
12847 * @extends Roo.Toolbar.Item
12848 * A simple element that adds extra horizontal space to a toolbar.
12850 * Creates a new Spacer
12852 Roo.Toolbar.Spacer = function(){
12853 var s = document.createElement("div");
12854 s.className = "ytb-spacer";
12855 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12857 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12858 enable:Roo.emptyFn,
12859 disable:Roo.emptyFn,
12864 * @class Roo.Toolbar.Fill
12865 * @extends Roo.Toolbar.Spacer
12866 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12868 * Creates a new Spacer
12870 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12872 render : function(td){
12873 td.style.width = '100%';
12874 Roo.Toolbar.Fill.superclass.render.call(this, td);
12879 * @class Roo.Toolbar.TextItem
12880 * @extends Roo.Toolbar.Item
12881 * A simple class that renders text directly into a toolbar.
12883 * Creates a new TextItem
12884 * @param {String} text
12886 Roo.Toolbar.TextItem = function(text){
12887 if (typeof(text) == 'object') {
12890 var s = document.createElement("span");
12891 s.className = "ytb-text";
12892 s.innerHTML = text;
12893 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12895 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12896 enable:Roo.emptyFn,
12897 disable:Roo.emptyFn,
12902 * @class Roo.Toolbar.Button
12903 * @extends Roo.Button
12904 * A button that renders into a toolbar.
12906 * Creates a new Button
12907 * @param {Object} config A standard {@link Roo.Button} config object
12909 Roo.Toolbar.Button = function(config){
12910 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12912 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12913 render : function(td){
12915 Roo.Toolbar.Button.superclass.render.call(this, td);
12919 * Removes and destroys this button
12921 destroy : function(){
12922 Roo.Toolbar.Button.superclass.destroy.call(this);
12923 this.td.parentNode.removeChild(this.td);
12927 * Shows this button
12930 this.hidden = false;
12931 this.td.style.display = "";
12935 * Hides this button
12938 this.hidden = true;
12939 this.td.style.display = "none";
12943 * Disables this item
12945 disable : function(){
12946 Roo.fly(this.td).addClass("x-item-disabled");
12947 this.disabled = true;
12951 * Enables this item
12953 enable : function(){
12954 Roo.fly(this.td).removeClass("x-item-disabled");
12955 this.disabled = false;
12958 // backwards compat
12959 Roo.ToolbarButton = Roo.Toolbar.Button;
12962 * @class Roo.Toolbar.SplitButton
12963 * @extends Roo.SplitButton
12964 * A menu button that renders into a toolbar.
12966 * Creates a new SplitButton
12967 * @param {Object} config A standard {@link Roo.SplitButton} config object
12969 Roo.Toolbar.SplitButton = function(config){
12970 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12972 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12973 render : function(td){
12975 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12979 * Removes and destroys this button
12981 destroy : function(){
12982 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12983 this.td.parentNode.removeChild(this.td);
12987 * Shows this button
12990 this.hidden = false;
12991 this.td.style.display = "";
12995 * Hides this button
12998 this.hidden = true;
12999 this.td.style.display = "none";
13003 // backwards compat
13004 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
13006 * Ext JS Library 1.1.1
13007 * Copyright(c) 2006-2007, Ext JS, LLC.
13009 * Originally Released Under LGPL - original licence link has changed is not relivant.
13012 * <script type="text/javascript">
13016 * @class Roo.PagingToolbar
13017 * @extends Roo.Toolbar
13018 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
13020 * Create a new PagingToolbar
13021 * @param {Object} config The config object
13023 Roo.PagingToolbar = function(el, ds, config)
13025 // old args format still supported... - xtype is prefered..
13026 if (typeof(el) == 'object' && el.xtype) {
13027 // created from xtype...
13029 ds = el.dataSource;
13030 el = config.container;
13033 if (config.items) {
13034 items = config.items;
13038 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
13041 this.renderButtons(this.el);
13044 // supprot items array.
13046 Roo.each(items, function(e) {
13047 this.add(Roo.factory(e));
13052 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
13054 * @cfg {Roo.data.Store} dataSource
13055 * The underlying data store providing the paged data
13058 * @cfg {String/HTMLElement/Element} container
13059 * container The id or element that will contain the toolbar
13062 * @cfg {Boolean} displayInfo
13063 * True to display the displayMsg (defaults to false)
13066 * @cfg {Number} pageSize
13067 * The number of records to display per page (defaults to 20)
13071 * @cfg {String} displayMsg
13072 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
13074 displayMsg : 'Displaying {0} - {1} of {2}',
13076 * @cfg {String} emptyMsg
13077 * The message to display when no records are found (defaults to "No data to display")
13079 emptyMsg : 'No data to display',
13081 * Customizable piece of the default paging text (defaults to "Page")
13084 beforePageText : "Page",
13086 * Customizable piece of the default paging text (defaults to "of %0")
13089 afterPageText : "of {0}",
13091 * Customizable piece of the default paging text (defaults to "First Page")
13094 firstText : "First Page",
13096 * Customizable piece of the default paging text (defaults to "Previous Page")
13099 prevText : "Previous Page",
13101 * Customizable piece of the default paging text (defaults to "Next Page")
13104 nextText : "Next Page",
13106 * Customizable piece of the default paging text (defaults to "Last Page")
13109 lastText : "Last Page",
13111 * Customizable piece of the default paging text (defaults to "Refresh")
13114 refreshText : "Refresh",
13117 renderButtons : function(el){
13118 Roo.PagingToolbar.superclass.render.call(this, el);
13119 this.first = this.addButton({
13120 tooltip: this.firstText,
13121 cls: "x-btn-icon x-grid-page-first",
13123 handler: this.onClick.createDelegate(this, ["first"])
13125 this.prev = this.addButton({
13126 tooltip: this.prevText,
13127 cls: "x-btn-icon x-grid-page-prev",
13129 handler: this.onClick.createDelegate(this, ["prev"])
13131 //this.addSeparator();
13132 this.add(this.beforePageText);
13133 this.field = Roo.get(this.addDom({
13138 cls: "x-grid-page-number"
13140 this.field.on("keydown", this.onPagingKeydown, this);
13141 this.field.on("focus", function(){this.dom.select();});
13142 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
13143 this.field.setHeight(18);
13144 //this.addSeparator();
13145 this.next = this.addButton({
13146 tooltip: this.nextText,
13147 cls: "x-btn-icon x-grid-page-next",
13149 handler: this.onClick.createDelegate(this, ["next"])
13151 this.last = this.addButton({
13152 tooltip: this.lastText,
13153 cls: "x-btn-icon x-grid-page-last",
13155 handler: this.onClick.createDelegate(this, ["last"])
13157 //this.addSeparator();
13158 this.loading = this.addButton({
13159 tooltip: this.refreshText,
13160 cls: "x-btn-icon x-grid-loading",
13161 handler: this.onClick.createDelegate(this, ["refresh"])
13164 if(this.displayInfo){
13165 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
13170 updateInfo : function(){
13171 if(this.displayEl){
13172 var count = this.ds.getCount();
13173 var msg = count == 0 ?
13177 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
13179 this.displayEl.update(msg);
13184 onLoad : function(ds, r, o){
13185 this.cursor = o.params ? o.params.start : 0;
13186 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
13188 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
13189 this.field.dom.value = ap;
13190 this.first.setDisabled(ap == 1);
13191 this.prev.setDisabled(ap == 1);
13192 this.next.setDisabled(ap == ps);
13193 this.last.setDisabled(ap == ps);
13194 this.loading.enable();
13199 getPageData : function(){
13200 var total = this.ds.getTotalCount();
13203 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
13204 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
13209 onLoadError : function(){
13210 this.loading.enable();
13214 onPagingKeydown : function(e){
13215 var k = e.getKey();
13216 var d = this.getPageData();
13218 var v = this.field.dom.value, pageNum;
13219 if(!v || isNaN(pageNum = parseInt(v, 10))){
13220 this.field.dom.value = d.activePage;
13223 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13224 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13227 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))
13229 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13230 this.field.dom.value = pageNum;
13231 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13234 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13236 var v = this.field.dom.value, pageNum;
13237 var increment = (e.shiftKey) ? 10 : 1;
13238 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13240 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13241 this.field.dom.value = d.activePage;
13244 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13246 this.field.dom.value = parseInt(v, 10) + increment;
13247 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13248 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13255 beforeLoad : function(){
13257 this.loading.disable();
13262 onClick : function(which){
13266 ds.load({params:{start: 0, limit: this.pageSize}});
13269 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13272 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13275 var total = ds.getTotalCount();
13276 var extra = total % this.pageSize;
13277 var lastStart = extra ? (total - extra) : total-this.pageSize;
13278 ds.load({params:{start: lastStart, limit: this.pageSize}});
13281 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13287 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13288 * @param {Roo.data.Store} store The data store to unbind
13290 unbind : function(ds){
13291 ds.un("beforeload", this.beforeLoad, this);
13292 ds.un("load", this.onLoad, this);
13293 ds.un("loadexception", this.onLoadError, this);
13294 ds.un("remove", this.updateInfo, this);
13295 ds.un("add", this.updateInfo, this);
13296 this.ds = undefined;
13300 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13301 * @param {Roo.data.Store} store The data store to bind
13303 bind : function(ds){
13304 ds.on("beforeload", this.beforeLoad, this);
13305 ds.on("load", this.onLoad, this);
13306 ds.on("loadexception", this.onLoadError, this);
13307 ds.on("remove", this.updateInfo, this);
13308 ds.on("add", this.updateInfo, this);