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);
7376 this.footer = this.list.createChild({cls:cls+'-ft'});
7377 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
7378 {pageSize: this.pageSize});
7382 if (this.pageTb && this.allowBlank && !this.disableClear) {
7384 this.pageTb.add(new Roo.Toolbar.Fill(), {
7385 cls: 'x-btn-icon x-btn-clear',
7391 _this.onSelect(false, -1);
7396 this.assetHeight += this.footer.getHeight();
7401 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
7404 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
7405 singleSelect:true, store: this.store, selectedClass: this.selectedClass
7407 //this.view.wrapEl.setDisplayed(false);
7408 this.view.on('click', this.onViewClick, this);
7412 this.store.on('beforeload', this.onBeforeLoad, this);
7413 this.store.on('load', this.onLoad, this);
7414 this.store.on('loadexception', this.onLoadException, this);
7417 this.resizer = new Roo.Resizable(this.list, {
7418 pinned:true, handles:'se'
7420 this.resizer.on('resize', function(r, w, h){
7421 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
7423 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
7424 this.restrictHeight();
7426 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
7430 this.editable = true;
7431 this.setEditable(false);
7436 if (typeof(this.events.add.listeners) != 'undefined') {
7438 this.addicon = this.wrap.createChild(
7439 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
7441 this.addicon.on('click', function(e) {
7442 this.fireEvent('add', this);
7445 if (typeof(this.events.edit.listeners) != 'undefined') {
7447 this.editicon = this.wrap.createChild(
7448 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
7450 this.editicon.setStyle('margin-left', '40px');
7452 this.editicon.on('click', function(e) {
7454 // we fire even if inothing is selected..
7455 this.fireEvent('edit', this, this.lastData );
7462 this.keyNav = new Roo.KeyNav(this.inputEl(), {
7464 this.inKeyMode = true;
7468 "down" : function(e){
7469 if(!this.isExpanded()){
7470 this.onTriggerClick();
7472 this.inKeyMode = true;
7477 "enter" : function(e){
7482 "esc" : function(e){
7486 "tab" : function(e){
7489 if(this.fireEvent("specialkey", this, e)){
7490 this.onViewClick(false);
7498 doRelay : function(foo, bar, hname){
7499 if(hname == 'down' || this.scope.isExpanded()){
7500 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
7509 this.queryDelay = Math.max(this.queryDelay || 10,
7510 this.mode == 'local' ? 10 : 250);
7513 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
7516 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
7518 if(this.editable !== false){
7519 this.inputEl().on("keyup", this.onKeyUp, this);
7521 if(this.forceSelection){
7522 this.on('blur', this.doForce, this);
7526 onDestroy : function(){
7528 this.view.setStore(null);
7529 this.view.el.removeAllListeners();
7530 this.view.el.remove();
7531 this.view.purgeListeners();
7534 this.list.dom.innerHTML = '';
7537 this.store.un('beforeload', this.onBeforeLoad, this);
7538 this.store.un('load', this.onLoad, this);
7539 this.store.un('loadexception', this.onLoadException, this);
7541 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
7545 fireKey : function(e){
7546 if(e.isNavKeyPress() && !this.list.isVisible()){
7547 this.fireEvent("specialkey", this, e);
7552 onResize: function(w, h){
7553 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
7555 // if(typeof w != 'number'){
7556 // // we do not handle it!?!?
7559 // var tw = this.trigger.getWidth();
7560 // // tw += this.addicon ? this.addicon.getWidth() : 0;
7561 // // tw += this.editicon ? this.editicon.getWidth() : 0;
7563 // this.inputEl().setWidth( this.adjustWidth('input', x));
7565 // //this.trigger.setStyle('left', x+'px');
7567 // if(this.list && this.listWidth === undefined){
7568 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
7569 // this.list.setWidth(lw);
7570 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7578 * Allow or prevent the user from directly editing the field text. If false is passed,
7579 * the user will only be able to select from the items defined in the dropdown list. This method
7580 * is the runtime equivalent of setting the 'editable' config option at config time.
7581 * @param {Boolean} value True to allow the user to directly edit the field text
7583 setEditable : function(value){
7584 if(value == this.editable){
7587 this.editable = value;
7589 this.inputEl().dom.setAttribute('readOnly', true);
7590 this.inputEl().on('mousedown', this.onTriggerClick, this);
7591 this.inputEl().addClass('x-combo-noedit');
7593 this.inputEl().dom.setAttribute('readOnly', false);
7594 this.inputEl().un('mousedown', this.onTriggerClick, this);
7595 this.inputEl().removeClass('x-combo-noedit');
7600 onBeforeLoad : function(){
7604 //this.innerList.update(this.loadingText ?
7605 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
7606 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
7608 this.restrictHeight();
7609 this.selectedIndex = -1;
7613 onLoad : function(){
7617 if(this.store.getCount() > 0){
7619 this.restrictHeight();
7620 if(this.lastQuery == this.allQuery){
7622 this.inputEl().dom.select();
7624 if(!this.selectByValue(this.value, true)){
7625 this.select(0, true);
7629 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
7630 this.taTask.delay(this.typeAheadDelay);
7634 this.onEmptyResults();
7639 onLoadException : function()
7642 Roo.log(this.store.reader.jsonData);
7643 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7645 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7651 onTypeAhead : function(){
7652 if(this.store.getCount() > 0){
7653 var r = this.store.getAt(0);
7654 var newValue = r.data[this.displayField];
7655 var len = newValue.length;
7656 var selStart = this.getRawValue().length;
7658 if(selStart != len){
7659 this.setRawValue(newValue);
7660 this.selectText(selStart, newValue.length);
7666 onSelect : function(record, index){
7667 if(this.fireEvent('beforeselect', this, record, index) !== false){
7668 this.setFromData(index > -1 ? record.data : false);
7670 this.fireEvent('select', this, record, index);
7675 * Returns the currently selected field value or empty string if no value is set.
7676 * @return {String} value The selected value
7678 getValue : function(){
7679 if(this.valueField){
7680 return typeof this.value != 'undefined' ? this.value : '';
7682 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
7687 * Clears any text/value currently set in the field
7689 clearValue : function(){
7690 if(this.hiddenField){
7691 this.hiddenField.dom.value = '';
7694 this.setRawValue('');
7695 this.lastSelectionText = '';
7700 * Sets the specified value into the field. If the value finds a match, the corresponding record text
7701 * will be displayed in the field. If the value does not match the data value of an existing item,
7702 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
7703 * Otherwise the field will be blank (although the value will still be set).
7704 * @param {String} value The value to match
7706 setValue : function(v){
7708 if(this.valueField){
7709 var r = this.findRecord(this.valueField, v);
7711 text = r.data[this.displayField];
7712 }else if(this.valueNotFoundText !== undefined){
7713 text = this.valueNotFoundText;
7716 this.lastSelectionText = text;
7717 if(this.hiddenField){
7718 this.hiddenField.dom.value = v;
7720 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
7724 * @property {Object} the last set data for the element
7729 * Sets the value of the field based on a object which is related to the record format for the store.
7730 * @param {Object} value the value to set as. or false on reset?
7732 setFromData : function(o){
7733 var dv = ''; // display value
7734 var vv = ''; // value value..
7736 if (this.displayField) {
7737 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
7739 // this is an error condition!!!
7740 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
7743 if(this.valueField){
7744 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
7746 if(this.hiddenField){
7747 this.hiddenField.dom.value = vv;
7749 this.lastSelectionText = dv;
7750 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7754 // no hidden field.. - we store the value in 'value', but still display
7755 // display field!!!!
7756 this.lastSelectionText = dv;
7757 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7764 // overridden so that last data is reset..
7765 this.setValue(this.originalValue);
7766 this.clearInvalid();
7767 this.lastData = false;
7769 this.view.clearSelections();
7773 findRecord : function(prop, value){
7775 if(this.store.getCount() > 0){
7776 this.store.each(function(r){
7777 if(r.data[prop] == value){
7789 // returns hidden if it's set..
7790 if (!this.rendered) {return ''};
7791 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
7795 onViewMove : function(e, t){
7796 this.inKeyMode = false;
7800 onViewOver : function(e, t){
7801 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
7804 var item = this.view.findItemFromChild(t);
7806 var index = this.view.indexOf(item);
7807 this.select(index, false);
7812 onViewClick : function(doFocus)
7814 var index = this.view.getSelectedIndexes()[0];
7815 var r = this.store.getAt(index);
7817 this.onSelect(r, index);
7819 if(doFocus !== false && !this.blockFocus){
7820 this.inputEl().focus();
7825 restrictHeight : function(){
7826 //this.innerList.dom.style.height = '';
7827 //var inner = this.innerList.dom;
7828 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
7829 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
7830 //this.list.beginUpdate();
7831 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
7832 this.list.alignTo(this.inputEl(), this.listAlign);
7833 //this.list.endUpdate();
7837 onEmptyResults : function(){
7842 * Returns true if the dropdown list is expanded, else false.
7844 isExpanded : function(){
7845 return this.list.isVisible();
7849 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
7850 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7851 * @param {String} value The data value of the item to select
7852 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7853 * selected item if it is not currently in view (defaults to true)
7854 * @return {Boolean} True if the value matched an item in the list, else false
7856 selectByValue : function(v, scrollIntoView){
7857 if(v !== undefined && v !== null){
7858 var r = this.findRecord(this.valueField || this.displayField, v);
7860 this.select(this.store.indexOf(r), scrollIntoView);
7868 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
7869 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7870 * @param {Number} index The zero-based index of the list item to select
7871 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7872 * selected item if it is not currently in view (defaults to true)
7874 select : function(index, scrollIntoView){
7875 this.selectedIndex = index;
7876 this.view.select(index);
7877 if(scrollIntoView !== false){
7878 var el = this.view.getNode(index);
7880 //this.innerList.scrollChildIntoView(el, false);
7887 selectNext : function(){
7888 var ct = this.store.getCount();
7890 if(this.selectedIndex == -1){
7892 }else if(this.selectedIndex < ct-1){
7893 this.select(this.selectedIndex+1);
7899 selectPrev : function(){
7900 var ct = this.store.getCount();
7902 if(this.selectedIndex == -1){
7904 }else if(this.selectedIndex != 0){
7905 this.select(this.selectedIndex-1);
7911 onKeyUp : function(e){
7912 if(this.editable !== false && !e.isSpecialKey()){
7913 this.lastKey = e.getKey();
7914 this.dqTask.delay(this.queryDelay);
7919 validateBlur : function(){
7920 return !this.list || !this.list.isVisible();
7924 initQuery : function(){
7925 this.doQuery(this.getRawValue());
7929 doForce : function(){
7930 if(this.el.dom.value.length > 0){
7932 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
7938 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
7939 * query allowing the query action to be canceled if needed.
7940 * @param {String} query The SQL query to execute
7941 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
7942 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
7943 * saved in the current store (defaults to false)
7945 doQuery : function(q, forceAll){
7946 if(q === undefined || q === null){
7955 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
7959 forceAll = qe.forceAll;
7960 if(forceAll === true || (q.length >= this.minChars)){
7961 if(this.lastQuery != q || this.alwaysQuery){
7963 if(this.mode == 'local'){
7964 this.selectedIndex = -1;
7966 this.store.clearFilter();
7968 this.store.filter(this.displayField, q);
7972 this.store.baseParams[this.queryParam] = q;
7974 params: this.getParams(q)
7979 this.selectedIndex = -1;
7986 getParams : function(q){
7988 //p[this.queryParam] = q;
7991 p.limit = this.pageSize;
7997 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
7999 collapse : function(){
8000 if(!this.isExpanded()){
8004 Roo.get(document).un('mousedown', this.collapseIf, this);
8005 Roo.get(document).un('mousewheel', this.collapseIf, this);
8006 if (!this.editable) {
8007 Roo.get(document).un('keydown', this.listKeyPress, this);
8009 this.fireEvent('collapse', this);
8013 collapseIf : function(e){
8014 if(!e.within(this.el) && !e.within(this.el)){
8020 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
8022 expand : function(){
8024 if(this.isExpanded() || !this.hasFocus){
8027 this.list.alignTo(this.inputEl(), this.listAlign);
8029 Roo.get(document).on('mousedown', this.collapseIf, this);
8030 Roo.get(document).on('mousewheel', this.collapseIf, this);
8031 if (!this.editable) {
8032 Roo.get(document).on('keydown', this.listKeyPress, this);
8035 this.fireEvent('expand', this);
8039 // Implements the default empty TriggerField.onTriggerClick function
8040 onTriggerClick : function()
8042 Roo.log('trigger click');
8047 if(this.isExpanded()){
8049 if (!this.blockFocus) {
8050 this.inputEl().focus();
8054 this.hasFocus = true;
8055 if(this.triggerAction == 'all') {
8056 this.doQuery(this.allQuery, true);
8058 this.doQuery(this.getRawValue());
8060 if (!this.blockFocus) {
8061 this.inputEl().focus();
8065 listKeyPress : function(e)
8067 //Roo.log('listkeypress');
8068 // scroll to first matching element based on key pres..
8069 if (e.isSpecialKey()) {
8072 var k = String.fromCharCode(e.getKey()).toUpperCase();
8075 var csel = this.view.getSelectedNodes();
8076 var cselitem = false;
8078 var ix = this.view.indexOf(csel[0]);
8079 cselitem = this.store.getAt(ix);
8080 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
8086 this.store.each(function(v) {
8088 // start at existing selection.
8089 if (cselitem.id == v.id) {
8095 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
8096 match = this.store.indexOf(v);
8102 if (match === false) {
8103 return true; // no more action?
8106 this.view.select(match);
8107 var sn = Roo.get(this.view.getSelectedNodes()[0])
8108 //sn.scrollIntoView(sn.dom.parentNode, false);
8112 * @cfg {Boolean} grow
8116 * @cfg {Number} growMin
8120 * @cfg {Number} growMax
8129 * Ext JS Library 1.1.1
8130 * Copyright(c) 2006-2007, Ext JS, LLC.
8132 * Originally Released Under LGPL - original licence link has changed is not relivant.
8135 * <script type="text/javascript">
8140 * @extends Roo.util.Observable
8141 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
8142 * This class also supports single and multi selection modes. <br>
8143 * Create a data model bound view:
8145 var store = new Roo.data.Store(...);
8147 var view = new Roo.View({
8149 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
8152 selectedClass: "ydataview-selected",
8156 // listen for node click?
8157 view.on("click", function(vw, index, node, e){
8158 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
8162 dataModel.load("foobar.xml");
8164 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
8166 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
8167 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
8169 * Note: old style constructor is still suported (container, template, config)
8173 * @param {Object} config The config object
8176 Roo.View = function(config, depreciated_tpl, depreciated_config){
8178 if (typeof(depreciated_tpl) == 'undefined') {
8179 // new way.. - universal constructor.
8180 Roo.apply(this, config);
8181 this.el = Roo.get(this.el);
8184 this.el = Roo.get(config);
8185 this.tpl = depreciated_tpl;
8186 Roo.apply(this, depreciated_config);
8188 this.wrapEl = this.el.wrap().wrap();
8189 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
8192 if(typeof(this.tpl) == "string"){
8193 this.tpl = new Roo.Template(this.tpl);
8195 // support xtype ctors..
8196 this.tpl = new Roo.factory(this.tpl, Roo);
8208 * @event beforeclick
8209 * Fires before a click is processed. Returns false to cancel the default action.
8210 * @param {Roo.View} this
8211 * @param {Number} index The index of the target node
8212 * @param {HTMLElement} node The target node
8213 * @param {Roo.EventObject} e The raw event object
8215 "beforeclick" : true,
8218 * Fires when a template node is clicked.
8219 * @param {Roo.View} this
8220 * @param {Number} index The index of the target node
8221 * @param {HTMLElement} node The target node
8222 * @param {Roo.EventObject} e The raw event object
8227 * Fires when a template node is double clicked.
8228 * @param {Roo.View} this
8229 * @param {Number} index The index of the target node
8230 * @param {HTMLElement} node The target node
8231 * @param {Roo.EventObject} e The raw event object
8235 * @event contextmenu
8236 * Fires when a template node is right clicked.
8237 * @param {Roo.View} this
8238 * @param {Number} index The index of the target node
8239 * @param {HTMLElement} node The target node
8240 * @param {Roo.EventObject} e The raw event object
8242 "contextmenu" : true,
8244 * @event selectionchange
8245 * Fires when the selected nodes change.
8246 * @param {Roo.View} this
8247 * @param {Array} selections Array of the selected nodes
8249 "selectionchange" : true,
8252 * @event beforeselect
8253 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
8254 * @param {Roo.View} this
8255 * @param {HTMLElement} node The node to be selected
8256 * @param {Array} selections Array of currently selected nodes
8258 "beforeselect" : true,
8260 * @event preparedata
8261 * Fires on every row to render, to allow you to change the data.
8262 * @param {Roo.View} this
8263 * @param {Object} data to be rendered (change this)
8265 "preparedata" : true
8273 "click": this.onClick,
8274 "dblclick": this.onDblClick,
8275 "contextmenu": this.onContextMenu,
8279 this.selections = [];
8281 this.cmp = new Roo.CompositeElementLite([]);
8283 this.store = Roo.factory(this.store, Roo.data);
8284 this.setStore(this.store, true);
8287 if ( this.footer && this.footer.xtype) {
8289 var fctr = this.wrapEl.appendChild(document.createElement("div"));
8291 this.footer.dataSource = this.store
8292 this.footer.container = fctr;
8293 this.footer = Roo.factory(this.footer, Roo);
8294 fctr.insertFirst(this.el);
8296 // this is a bit insane - as the paging toolbar seems to detach the el..
8297 // dom.parentNode.parentNode.parentNode
8298 // they get detached?
8302 Roo.View.superclass.constructor.call(this);
8307 Roo.extend(Roo.View, Roo.util.Observable, {
8310 * @cfg {Roo.data.Store} store Data store to load data from.
8315 * @cfg {String|Roo.Element} el The container element.
8320 * @cfg {String|Roo.Template} tpl The template used by this View
8324 * @cfg {String} dataName the named area of the template to use as the data area
8325 * Works with domtemplates roo-name="name"
8329 * @cfg {String} selectedClass The css class to add to selected nodes
8331 selectedClass : "x-view-selected",
8333 * @cfg {String} emptyText The empty text to show when nothing is loaded.
8338 * @cfg {String} text to display on mask (default Loading)
8342 * @cfg {Boolean} multiSelect Allow multiple selection
8344 multiSelect : false,
8346 * @cfg {Boolean} singleSelect Allow single selection
8348 singleSelect: false,
8351 * @cfg {Boolean} toggleSelect - selecting
8353 toggleSelect : false,
8356 * Returns the element this view is bound to.
8357 * @return {Roo.Element}
8366 * Refreshes the view. - called by datachanged on the store. - do not call directly.
8368 refresh : function(){
8371 // if we are using something like 'domtemplate', then
8372 // the what gets used is:
8373 // t.applySubtemplate(NAME, data, wrapping data..)
8374 // the outer template then get' applied with
8375 // the store 'extra data'
8376 // and the body get's added to the
8377 // roo-name="data" node?
8378 // <span class='roo-tpl-{name}'></span> ?????
8382 this.clearSelections();
8385 var records = this.store.getRange();
8386 if(records.length < 1) {
8388 // is this valid?? = should it render a template??
8390 this.el.update(this.emptyText);
8394 if (this.dataName) {
8395 this.el.update(t.apply(this.store.meta)); //????
8396 el = this.el.child('.roo-tpl-' + this.dataName);
8399 for(var i = 0, len = records.length; i < len; i++){
8400 var data = this.prepareData(records[i].data, i, records[i]);
8401 this.fireEvent("preparedata", this, data, i, records[i]);
8402 html[html.length] = Roo.util.Format.trim(
8404 t.applySubtemplate(this.dataName, data, this.store.meta) :
8411 el.update(html.join(""));
8412 this.nodes = el.dom.childNodes;
8413 this.updateIndexes(0);
8417 * Function to override to reformat the data that is sent to
8418 * the template for each node.
8419 * DEPRICATED - use the preparedata event handler.
8420 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
8421 * a JSON object for an UpdateManager bound view).
8423 prepareData : function(data, index, record)
8425 this.fireEvent("preparedata", this, data, index, record);
8429 onUpdate : function(ds, record){
8430 this.clearSelections();
8431 var index = this.store.indexOf(record);
8432 var n = this.nodes[index];
8433 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
8434 n.parentNode.removeChild(n);
8435 this.updateIndexes(index, index);
8441 onAdd : function(ds, records, index)
8443 this.clearSelections();
8444 if(this.nodes.length == 0){
8448 var n = this.nodes[index];
8449 for(var i = 0, len = records.length; i < len; i++){
8450 var d = this.prepareData(records[i].data, i, records[i]);
8452 this.tpl.insertBefore(n, d);
8455 this.tpl.append(this.el, d);
8458 this.updateIndexes(index);
8461 onRemove : function(ds, record, index){
8462 this.clearSelections();
8463 var el = this.dataName ?
8464 this.el.child('.roo-tpl-' + this.dataName) :
8466 el.dom.removeChild(this.nodes[index]);
8467 this.updateIndexes(index);
8471 * Refresh an individual node.
8472 * @param {Number} index
8474 refreshNode : function(index){
8475 this.onUpdate(this.store, this.store.getAt(index));
8478 updateIndexes : function(startIndex, endIndex){
8479 var ns = this.nodes;
8480 startIndex = startIndex || 0;
8481 endIndex = endIndex || ns.length - 1;
8482 for(var i = startIndex; i <= endIndex; i++){
8483 ns[i].nodeIndex = i;
8488 * Changes the data store this view uses and refresh the view.
8489 * @param {Store} store
8491 setStore : function(store, initial){
8492 if(!initial && this.store){
8493 this.store.un("datachanged", this.refresh);
8494 this.store.un("add", this.onAdd);
8495 this.store.un("remove", this.onRemove);
8496 this.store.un("update", this.onUpdate);
8497 this.store.un("clear", this.refresh);
8498 this.store.un("beforeload", this.onBeforeLoad);
8499 this.store.un("load", this.onLoad);
8500 this.store.un("loadexception", this.onLoad);
8504 store.on("datachanged", this.refresh, this);
8505 store.on("add", this.onAdd, this);
8506 store.on("remove", this.onRemove, this);
8507 store.on("update", this.onUpdate, this);
8508 store.on("clear", this.refresh, this);
8509 store.on("beforeload", this.onBeforeLoad, this);
8510 store.on("load", this.onLoad, this);
8511 store.on("loadexception", this.onLoad, this);
8519 * onbeforeLoad - masks the loading area.
8522 onBeforeLoad : function()
8525 this.el.mask(this.mask ? this.mask : "Loading" );
8527 onLoad : function ()
8534 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
8535 * @param {HTMLElement} node
8536 * @return {HTMLElement} The template node
8538 findItemFromChild : function(node){
8539 var el = this.dataName ?
8540 this.el.child('.roo-tpl-' + this.dataName,true) :
8543 if(!node || node.parentNode == el){
8546 var p = node.parentNode;
8547 while(p && p != el){
8548 if(p.parentNode == el){
8557 onClick : function(e){
8558 var item = this.findItemFromChild(e.getTarget());
8560 var index = this.indexOf(item);
8561 if(this.onItemClick(item, index, e) !== false){
8562 this.fireEvent("click", this, index, item, e);
8565 this.clearSelections();
8570 onContextMenu : function(e){
8571 var item = this.findItemFromChild(e.getTarget());
8573 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
8578 onDblClick : function(e){
8579 var item = this.findItemFromChild(e.getTarget());
8581 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
8585 onItemClick : function(item, index, e)
8587 if(this.fireEvent("beforeclick", this, index, item, e) === false){
8590 if (this.toggleSelect) {
8591 var m = this.isSelected(item) ? 'unselect' : 'select';
8594 _t[m](item, true, false);
8597 if(this.multiSelect || this.singleSelect){
8598 if(this.multiSelect && e.shiftKey && this.lastSelection){
8599 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
8601 this.select(item, this.multiSelect && e.ctrlKey);
8602 this.lastSelection = item;
8610 * Get the number of selected nodes.
8613 getSelectionCount : function(){
8614 return this.selections.length;
8618 * Get the currently selected nodes.
8619 * @return {Array} An array of HTMLElements
8621 getSelectedNodes : function(){
8622 return this.selections;
8626 * Get the indexes of the selected nodes.
8629 getSelectedIndexes : function(){
8630 var indexes = [], s = this.selections;
8631 for(var i = 0, len = s.length; i < len; i++){
8632 indexes.push(s[i].nodeIndex);
8638 * Clear all selections
8639 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
8641 clearSelections : function(suppressEvent){
8642 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
8643 this.cmp.elements = this.selections;
8644 this.cmp.removeClass(this.selectedClass);
8645 this.selections = [];
8647 this.fireEvent("selectionchange", this, this.selections);
8653 * Returns true if the passed node is selected
8654 * @param {HTMLElement/Number} node The node or node index
8657 isSelected : function(node){
8658 var s = this.selections;
8662 node = this.getNode(node);
8663 return s.indexOf(node) !== -1;
8668 * @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
8669 * @param {Boolean} keepExisting (optional) true to keep existing selections
8670 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8672 select : function(nodeInfo, keepExisting, suppressEvent){
8673 if(nodeInfo instanceof Array){
8675 this.clearSelections(true);
8677 for(var i = 0, len = nodeInfo.length; i < len; i++){
8678 this.select(nodeInfo[i], true, true);
8682 var node = this.getNode(nodeInfo);
8683 if(!node || this.isSelected(node)){
8684 return; // already selected.
8687 this.clearSelections(true);
8689 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
8690 Roo.fly(node).addClass(this.selectedClass);
8691 this.selections.push(node);
8693 this.fireEvent("selectionchange", this, this.selections);
8701 * @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
8702 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
8703 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8705 unselect : function(nodeInfo, keepExisting, suppressEvent)
8707 if(nodeInfo instanceof Array){
8708 Roo.each(this.selections, function(s) {
8709 this.unselect(s, nodeInfo);
8713 var node = this.getNode(nodeInfo);
8714 if(!node || !this.isSelected(node)){
8715 Roo.log("not selected");
8716 return; // not selected.
8720 Roo.each(this.selections, function(s) {
8722 Roo.fly(node).removeClass(this.selectedClass);
8729 this.selections= ns;
8730 this.fireEvent("selectionchange", this, this.selections);
8734 * Gets a template node.
8735 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8736 * @return {HTMLElement} The node or null if it wasn't found
8738 getNode : function(nodeInfo){
8739 if(typeof nodeInfo == "string"){
8740 return document.getElementById(nodeInfo);
8741 }else if(typeof nodeInfo == "number"){
8742 return this.nodes[nodeInfo];
8748 * Gets a range template nodes.
8749 * @param {Number} startIndex
8750 * @param {Number} endIndex
8751 * @return {Array} An array of nodes
8753 getNodes : function(start, end){
8754 var ns = this.nodes;
8756 end = typeof end == "undefined" ? ns.length - 1 : end;
8759 for(var i = start; i <= end; i++){
8763 for(var i = start; i >= end; i--){
8771 * Finds the index of the passed node
8772 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8773 * @return {Number} The index of the node or -1
8775 indexOf : function(node){
8776 node = this.getNode(node);
8777 if(typeof node.nodeIndex == "number"){
8778 return node.nodeIndex;
8780 var ns = this.nodes;
8781 for(var i = 0, len = ns.length; i < len; i++){
8792 * based on jquery fullcalendar
8796 Roo.bootstrap = Roo.bootstrap || {};
8798 * @class Roo.bootstrap.Calendar
8799 * @extends Roo.bootstrap.Component
8800 * Bootstrap Calendar class
8801 * @cfg {Boolean} loadMask (true|false) default false
8804 * Create a new Container
8805 * @param {Object} config The config object
8810 Roo.bootstrap.Calendar = function(config){
8811 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
8815 * Fires when a date is selected
8816 * @param {DatePicker} this
8817 * @param {Date} date The selected date
8821 * @event monthchange
8822 * Fires when the displayed month changes
8823 * @param {DatePicker} this
8824 * @param {Date} date The selected month
8826 'monthchange': true,
8829 * Fires when mouse over an event
8830 * @param {Calendar} this
8831 * @param {event} Event
8836 * Fires when the mouse leaves an
8837 * @param {Calendar} this
8843 * Fires when the mouse click an
8844 * @param {Calendar} this
8853 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
8856 * @cfg {Number} startDay
8857 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
8863 getAutoCreate : function(){
8866 var fc_button = function(name, corner, style, content ) {
8867 return Roo.apply({},{
8869 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
8871 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
8874 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
8882 style : 'width:100%',
8889 cls : 'fc-header-left',
8891 fc_button('prev', 'left', 'arrow', '‹' ),
8892 fc_button('next', 'right', 'arrow', '›' ),
8893 { tag: 'span', cls: 'fc-header-space' },
8894 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
8902 cls : 'fc-header-center',
8906 cls: 'fc-header-title',
8909 html : 'month / year'
8917 cls : 'fc-header-right',
8919 /* fc_button('month', 'left', '', 'month' ),
8920 fc_button('week', '', '', 'week' ),
8921 fc_button('day', 'right', '', 'day' )
8933 var cal_heads = function() {
8935 // fixme - handle this.
8937 for (var i =0; i < Date.dayNames.length; i++) {
8938 var d = Date.dayNames[i];
8941 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
8942 html : d.substring(0,3)
8946 ret[0].cls += ' fc-first';
8947 ret[6].cls += ' fc-last';
8950 var cal_cell = function(n) {
8953 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
8958 cls: 'fc-day-number',
8962 cls: 'fc-day-content',
8966 style: 'position: relative;' // height: 17px;
8978 var cal_rows = function() {
8981 for (var r = 0; r < 6; r++) {
8988 for (var i =0; i < Date.dayNames.length; i++) {
8989 var d = Date.dayNames[i];
8990 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
8993 row.cn[0].cls+=' fc-first';
8994 row.cn[0].cn[0].style = 'min-height:90px';
8995 row.cn[6].cls+=' fc-last';
8999 ret[0].cls += ' fc-first';
9000 ret[4].cls += ' fc-prev-last';
9001 ret[5].cls += ' fc-last';
9008 cls: 'fc-border-separate',
9009 style : 'width:100%',
9017 cls : 'fc-first fc-last',
9036 style : "position: relative;",
9039 cls : 'fc-view fc-view-month fc-grid',
9040 style : 'position: relative',
9041 unselectable : 'on',
9044 cls : 'fc-event-container',
9045 style : 'position:absolute;z-index:8;top:0;left:0;'
9063 initEvents : function()
9066 throw "can not find store for calendar";
9072 style: "text-align:center",
9076 style: "background-color:white;width:50%;margin:250 auto",
9080 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
9091 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
9093 var size = this.el.select('.fc-content', true).first().getSize();
9094 this.maskEl.setSize(size.width, size.height);
9095 this.maskEl.enableDisplayMode("block");
9100 this.store = Roo.factory(this.store, Roo.data);
9101 this.store.on('load', this.onLoad, this);
9102 this.store.on('beforeload', this.onBeforeLoad, this);
9106 this.cells = this.el.select('.fc-day',true);
9107 //Roo.log(this.cells);
9108 this.textNodes = this.el.query('.fc-day-number');
9109 this.cells.addClassOnOver('fc-state-hover');
9111 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
9112 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
9113 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
9114 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
9116 this.on('monthchange', this.onMonthChange, this);
9118 // this.update(new Date().clearTime());
9121 resize : function() {
9122 var sz = this.el.getSize();
9124 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
9125 this.el.select('.fc-day-content div',true).setHeight(34);
9130 showPrevMonth : function(e){
9131 this.update(this.activeDate.add("mo", -1));
9133 showToday : function(e){
9134 this.update(new Date().clearTime());
9137 showNextMonth : function(e){
9138 this.update(this.activeDate.add("mo", 1));
9142 showPrevYear : function(){
9143 this.update(this.activeDate.add("y", -1));
9147 showNextYear : function(){
9148 this.update(this.activeDate.add("y", 1));
9153 update : function(date)
9155 var vd = this.activeDate;
9156 this.activeDate = date;
9157 // if(vd && this.el){
9158 // var t = date.getTime();
9159 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
9160 // Roo.log('using add remove');
9162 // this.fireEvent('monthchange', this, date);
9164 // this.cells.removeClass("fc-state-highlight");
9165 // this.cells.each(function(c){
9166 // if(c.dateValue == t){
9167 // c.addClass("fc-state-highlight");
9168 // setTimeout(function(){
9169 // try{c.dom.firstChild.focus();}catch(e){}
9179 var days = date.getDaysInMonth();
9181 var firstOfMonth = date.getFirstDateOfMonth();
9182 var startingPos = firstOfMonth.getDay()-this.startDay;
9184 if(startingPos < this.startDay){
9188 var pm = date.add(Date.MONTH, -1);
9189 var prevStart = pm.getDaysInMonth()-startingPos;
9191 this.cells = this.el.select('.fc-day',true);
9192 this.textNodes = this.el.query('.fc-day-number');
9193 this.cells.addClassOnOver('fc-state-hover');
9195 var cells = this.cells.elements;
9196 var textEls = this.textNodes;
9198 Roo.each(cells, function(cell){
9199 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
9202 days += startingPos;
9204 // convert everything to numbers so it's fast
9206 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
9209 //Roo.log(prevStart);
9211 var today = new Date().clearTime().getTime();
9212 var sel = date.clearTime().getTime();
9213 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
9214 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
9215 var ddMatch = this.disabledDatesRE;
9216 var ddText = this.disabledDatesText;
9217 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
9218 var ddaysText = this.disabledDaysText;
9219 var format = this.format;
9221 var setCellClass = function(cal, cell){
9223 //Roo.log('set Cell Class');
9225 var t = d.getTime();
9231 cell.className += " fc-today";
9232 cell.className += " fc-state-highlight";
9233 cell.title = cal.todayText;
9236 // disable highlight in other month..
9237 //cell.className += " fc-state-highlight";
9242 cell.className = " fc-state-disabled";
9243 cell.title = cal.minText;
9247 cell.className = " fc-state-disabled";
9248 cell.title = cal.maxText;
9252 if(ddays.indexOf(d.getDay()) != -1){
9253 cell.title = ddaysText;
9254 cell.className = " fc-state-disabled";
9257 if(ddMatch && format){
9258 var fvalue = d.dateFormat(format);
9259 if(ddMatch.test(fvalue)){
9260 cell.title = ddText.replace("%0", fvalue);
9261 cell.className = " fc-state-disabled";
9265 if (!cell.initialClassName) {
9266 cell.initialClassName = cell.dom.className;
9269 cell.dom.className = cell.initialClassName + ' ' + cell.className;
9274 for(; i < startingPos; i++) {
9275 textEls[i].innerHTML = (++prevStart);
9276 d.setDate(d.getDate()+1);
9278 cells[i].className = "fc-past fc-other-month";
9279 setCellClass(this, cells[i]);
9284 for(; i < days; i++){
9285 intDay = i - startingPos + 1;
9286 textEls[i].innerHTML = (intDay);
9287 d.setDate(d.getDate()+1);
9289 cells[i].className = ''; // "x-date-active";
9290 setCellClass(this, cells[i]);
9294 for(; i < 42; i++) {
9295 textEls[i].innerHTML = (++extraDays);
9296 d.setDate(d.getDate()+1);
9298 cells[i].className = "fc-future fc-other-month";
9299 setCellClass(this, cells[i]);
9302 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
9304 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
9306 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
9307 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
9310 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
9311 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
9314 this.fireEvent('monthchange', this, date);
9318 if(!this.internalRender){
9319 var main = this.el.dom.firstChild;
9320 var w = main.offsetWidth;
9321 this.el.setWidth(w + this.el.getBorderWidth("lr"));
9322 Roo.fly(main).setWidth(w);
9323 this.internalRender = true;
9324 // opera does not respect the auto grow header center column
9325 // then, after it gets a width opera refuses to recalculate
9326 // without a second pass
9327 if(Roo.isOpera && !this.secondPass){
9328 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
9329 this.secondPass = true;
9330 this.update.defer(10, this, [date]);
9337 findCell : function(dt) {
9338 dt = dt.clearTime().getTime();
9340 this.cells.each(function(c){
9341 //Roo.log("check " +c.dateValue + '?=' + dt);
9342 if(c.dateValue == dt){
9352 findCells : function(ev) {
9353 var s = ev.start.clone().clearTime().getTime();
9355 var e= ev.end.clone().clearTime().getTime();
9358 this.cells.each(function(c){
9359 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
9361 if(c.dateValue > e){
9364 if(c.dateValue < s){
9373 findBestRow: function(cells)
9377 for (var i =0 ; i < cells.length;i++) {
9378 ret = Math.max(cells[i].rows || 0,ret);
9385 addItem : function(ev)
9387 // look for vertical location slot in
9388 var cells = this.findCells(ev);
9390 ev.row = this.findBestRow(cells);
9392 // work out the location.
9396 for(var i =0; i < cells.length; i++) {
9404 if (crow.start.getY() == cells[i].getY()) {
9406 crow.end = cells[i];
9422 for (var i = 0; i < cells.length;i++) {
9423 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
9427 this.calevents.push(ev);
9430 clearEvents: function() {
9432 if(!this.calevents){
9436 Roo.each(this.cells.elements, function(c){
9440 Roo.each(this.calevents, function(e) {
9441 Roo.each(e.els, function(el) {
9442 el.un('mouseenter' ,this.onEventEnter, this);
9443 el.un('mouseleave' ,this.onEventLeave, this);
9450 renderEvents: function()
9452 // first make sure there is enough space..
9454 this.cells.each(function(c) {
9456 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
9459 for (var e = 0; e < this.calevents.length; e++) {
9460 var ev = this.calevents[e];
9461 var cells = ev.cells;
9464 for(var i =0; i < rows.length; i++) {
9467 // how many rows should it span..
9470 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
9471 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
9473 unselectable : "on",
9476 cls: 'fc-event-inner',
9480 cls: 'fc-event-time',
9481 html : cells.length > 1 ? '' : ev.time
9485 cls: 'fc-event-title',
9486 html : String.format('{0}', ev.title)
9493 cls: 'ui-resizable-handle ui-resizable-e',
9494 html : '  '
9500 cfg.cls += ' fc-event-start';
9502 if ((i+1) == rows.length) {
9503 cfg.cls += ' fc-event-end';
9506 var ctr = this.el.select('.fc-event-container',true).first();
9507 var cg = ctr.createChild(cfg);
9509 cg.on('mouseenter' ,this.onEventEnter, this, ev);
9510 cg.on('mouseleave' ,this.onEventLeave, this, ev);
9511 cg.on('click', this.onEventClick, this, ev);
9515 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
9516 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
9518 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
9519 cg.setWidth(ebox.right - sbox.x -2);
9527 onEventEnter: function (e, el,event,d) {
9528 this.fireEvent('evententer', this, el, event);
9531 onEventLeave: function (e, el,event,d) {
9532 this.fireEvent('eventleave', this, el, event);
9535 onEventClick: function (e, el,event,d) {
9536 this.fireEvent('eventclick', this, el, event);
9539 onMonthChange: function () {
9545 this.calevents = [];
9547 if(this.store.getCount() > 0){
9548 this.store.data.each(function(d){
9551 start: new Date(d.data.start_dt),
9552 end : new Date(d.data.end_dt),
9553 time : d.data.start_time,
9554 title : d.data.title,
9555 description : d.data.description,
9556 venue : d.data.venue
9561 this.renderEvents();
9568 onBeforeLoad: function()
9587 * @class Roo.bootstrap.Popover
9588 * @extends Roo.bootstrap.Component
9589 * Bootstrap Popover class
9590 * @cfg {String} html contents of the popover (or false to use children..)
9591 * @cfg {String} title of popover (or false to hide)
9592 * @cfg {String} placement how it is placed
9593 * @cfg {String} trigger click || hover (or false to trigger manually)
9594 * @cfg {String} over what (parent or false to trigger manually.)
9597 * Create a new Popover
9598 * @param {Object} config The config object
9601 Roo.bootstrap.Popover = function(config){
9602 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
9605 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
9607 title: 'Fill in a title',
9610 placement : 'right',
9611 trigger : 'hover', // hover
9615 can_build_overlaid : false,
9617 getChildContainer : function()
9619 return this.el.select('.popover-content',true).first();
9622 getAutoCreate : function(){
9623 Roo.log('make popover?');
9625 cls : 'popover roo-dynamic',
9626 style: 'display:block',
9632 cls : 'popover-inner',
9636 cls: 'popover-title',
9640 cls : 'popover-content',
9651 setTitle: function(str)
9653 this.el.select('.popover-title',true).first().dom.innerHTML = str;
9655 setContent: function(str)
9657 this.el.select('.popover-content',true).first().dom.innerHTML = str;
9659 // as it get's added to the bottom of the page.
9660 onRender : function(ct, position)
9662 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
9664 var cfg = Roo.apply({}, this.getAutoCreate());
9668 cfg.cls += ' ' + this.cls;
9671 cfg.style = this.style;
9673 Roo.log("adding to ")
9674 this.el = Roo.get(document.body).createChild(cfg, position);
9680 initEvents : function()
9682 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
9683 this.el.enableDisplayMode('block');
9685 if (this.over === false) {
9688 if (this.triggers === false) {
9691 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9692 var triggers = this.trigger ? this.trigger.split(' ') : [];
9693 Roo.each(triggers, function(trigger) {
9695 if (trigger == 'click') {
9696 on_el.on('click', this.toggle, this);
9697 } else if (trigger != 'manual') {
9698 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
9699 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
9701 on_el.on(eventIn ,this.enter, this);
9702 on_el.on(eventOut, this.leave, this);
9713 toggle : function () {
9714 this.hoverState == 'in' ? this.leave() : this.enter();
9717 enter : function () {
9720 clearTimeout(this.timeout);
9722 this.hoverState = 'in'
9724 if (!this.delay || !this.delay.show) {
9729 this.timeout = setTimeout(function () {
9730 if (_t.hoverState == 'in') {
9735 leave : function() {
9736 clearTimeout(this.timeout);
9738 this.hoverState = 'out'
9740 if (!this.delay || !this.delay.hide) {
9745 this.timeout = setTimeout(function () {
9746 if (_t.hoverState == 'out') {
9752 show : function (on_el)
9755 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9758 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
9759 if (this.html !== false) {
9760 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
9762 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
9763 if (!this.title.length) {
9764 this.el.select('.popover-title',true).hide();
9767 var placement = typeof this.placement == 'function' ?
9768 this.placement.call(this, this.el, on_el) :
9771 var autoToken = /\s?auto?\s?/i;
9772 var autoPlace = autoToken.test(placement);
9774 placement = placement.replace(autoToken, '') || 'top';
9778 //this.el.setXY([0,0]);
9780 this.el.dom.style.display='block';
9781 this.el.addClass(placement);
9783 //this.el.appendTo(on_el);
9785 var p = this.getPosition();
9786 var box = this.el.getBox();
9791 var align = Roo.bootstrap.Popover.alignment[placement]
9792 this.el.alignTo(on_el, align[0],align[1]);
9793 //var arrow = this.el.select('.arrow',true).first();
9794 //arrow.set(align[2],
9796 this.el.addClass('in');
9797 this.hoverState = null;
9799 if (this.el.hasClass('fade')) {
9806 this.el.setXY([0,0]);
9807 this.el.removeClass('in');
9814 Roo.bootstrap.Popover.alignment = {
9815 'left' : ['r-l', [-10,0], 'right'],
9816 'right' : ['l-r', [10,0], 'left'],
9817 'bottom' : ['t-b', [0,10], 'top'],
9818 'top' : [ 'b-t', [0,-10], 'bottom']
9829 * @class Roo.bootstrap.Progress
9830 * @extends Roo.bootstrap.Component
9831 * Bootstrap Progress class
9832 * @cfg {Boolean} striped striped of the progress bar
9833 * @cfg {Boolean} active animated of the progress bar
9837 * Create a new Progress
9838 * @param {Object} config The config object
9841 Roo.bootstrap.Progress = function(config){
9842 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
9845 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
9850 getAutoCreate : function(){
9858 cfg.cls += ' progress-striped';
9862 cfg.cls += ' active';
9881 * @class Roo.bootstrap.ProgressBar
9882 * @extends Roo.bootstrap.Component
9883 * Bootstrap ProgressBar class
9884 * @cfg {Number} aria_valuenow aria-value now
9885 * @cfg {Number} aria_valuemin aria-value min
9886 * @cfg {Number} aria_valuemax aria-value max
9887 * @cfg {String} label label for the progress bar
9888 * @cfg {String} panel (success | info | warning | danger )
9889 * @cfg {String} role role of the progress bar
9890 * @cfg {String} sr_only text
9894 * Create a new ProgressBar
9895 * @param {Object} config The config object
9898 Roo.bootstrap.ProgressBar = function(config){
9899 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
9902 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
9906 aria_valuemax : 100,
9912 getAutoCreate : function()
9917 cls: 'progress-bar',
9918 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
9930 cfg.role = this.role;
9933 if(this.aria_valuenow){
9934 cfg['aria-valuenow'] = this.aria_valuenow;
9937 if(this.aria_valuemin){
9938 cfg['aria-valuemin'] = this.aria_valuemin;
9941 if(this.aria_valuemax){
9942 cfg['aria-valuemax'] = this.aria_valuemax;
9945 if(this.label && !this.sr_only){
9946 cfg.html = this.label;
9950 cfg.cls += ' progress-bar-' + this.panel;
9956 update : function(aria_valuenow)
9958 this.aria_valuenow = aria_valuenow;
9960 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
9975 * @class Roo.bootstrap.TabPanel
9976 * @extends Roo.bootstrap.Component
9977 * Bootstrap TabPanel class
9978 * @cfg {Boolean} active panel active
9979 * @cfg {String} html panel content
9980 * @cfg {String} tabId tab relate id
9984 * Create a new TabPanel
9985 * @param {Object} config The config object
9988 Roo.bootstrap.TabPanel = function(config){
9989 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
9992 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
9998 getAutoCreate : function(){
10002 html: this.html || ''
10006 cfg.cls += ' active';
10010 cfg.tabId = this.tabId;
10028 * @class Roo.bootstrap.DateField
10029 * @extends Roo.bootstrap.Input
10030 * Bootstrap DateField class
10031 * @cfg {Number} weekStart default 0
10032 * @cfg {Number} weekStart default 0
10033 * @cfg {Number} viewMode default empty, (months|years)
10034 * @cfg {Number} minViewMode default empty, (months|years)
10035 * @cfg {Number} startDate default -Infinity
10036 * @cfg {Number} endDate default Infinity
10037 * @cfg {Boolean} todayHighlight default false
10038 * @cfg {Boolean} todayBtn default false
10039 * @cfg {Boolean} calendarWeeks default false
10040 * @cfg {Object} daysOfWeekDisabled default empty
10042 * @cfg {Boolean} keyboardNavigation default true
10043 * @cfg {String} language default en
10046 * Create a new DateField
10047 * @param {Object} config The config object
10050 Roo.bootstrap.DateField = function(config){
10051 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
10054 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
10057 * @cfg {String} format
10058 * The default date format string which can be overriden for localization support. The format must be
10059 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10063 * @cfg {String} altFormats
10064 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
10065 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
10067 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
10075 todayHighlight : false,
10081 keyboardNavigation: true,
10083 calendarWeeks: false,
10085 startDate: -Infinity,
10089 daysOfWeekDisabled: [],
10093 UTCDate: function()
10095 return new Date(Date.UTC.apply(Date, arguments));
10098 UTCToday: function()
10100 var today = new Date();
10101 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
10104 getDate: function() {
10105 var d = this.getUTCDate();
10106 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
10109 getUTCDate: function() {
10113 setDate: function(d) {
10114 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
10117 setUTCDate: function(d) {
10119 this.setValue(this.formatDate(this.date));
10122 onRender: function(ct, position)
10125 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
10127 this.language = this.language || 'en';
10128 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
10129 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
10131 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
10132 this.format = this.format || 'm/d/y';
10133 this.isInline = false;
10134 this.isInput = true;
10135 this.component = this.el.select('.add-on', true).first() || false;
10136 this.component = (this.component && this.component.length === 0) ? false : this.component;
10137 this.hasInput = this.component && this.inputEL().length;
10139 if (typeof(this.minViewMode === 'string')) {
10140 switch (this.minViewMode) {
10142 this.minViewMode = 1;
10145 this.minViewMode = 2;
10148 this.minViewMode = 0;
10153 if (typeof(this.viewMode === 'string')) {
10154 switch (this.viewMode) {
10167 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
10169 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10171 this.picker().on('mousedown', this.onMousedown, this);
10172 this.picker().on('click', this.onClick, this);
10174 this.picker().addClass('datepicker-dropdown');
10176 this.startViewMode = this.viewMode;
10179 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
10180 if(!this.calendarWeeks){
10185 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
10186 v.attr('colspan', function(i, val){
10187 return parseInt(val) + 1;
10192 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
10194 this.setStartDate(this.startDate);
10195 this.setEndDate(this.endDate);
10197 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
10204 if(this.isInline) {
10209 picker : function()
10211 return this.el.select('.datepicker', true).first();
10214 fillDow: function()
10216 var dowCnt = this.weekStart;
10225 if(this.calendarWeeks){
10233 while (dowCnt < this.weekStart + 7) {
10237 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
10241 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
10244 fillMonths: function()
10247 var months = this.picker().select('>.datepicker-months td', true).first();
10249 months.dom.innerHTML = '';
10255 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
10258 months.createChild(month);
10263 update: function(){
10265 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
10267 if (this.date < this.startDate) {
10268 this.viewDate = new Date(this.startDate);
10269 } else if (this.date > this.endDate) {
10270 this.viewDate = new Date(this.endDate);
10272 this.viewDate = new Date(this.date);
10279 var d = new Date(this.viewDate),
10280 year = d.getUTCFullYear(),
10281 month = d.getUTCMonth(),
10282 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
10283 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
10284 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
10285 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
10286 currentDate = this.date && this.date.valueOf(),
10287 today = this.UTCToday();
10289 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
10291 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
10293 // this.picker.select('>tfoot th.today').
10294 // .text(dates[this.language].today)
10295 // .toggle(this.todayBtn !== false);
10297 this.updateNavArrows();
10300 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
10302 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
10304 prevMonth.setUTCDate(day);
10306 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
10308 var nextMonth = new Date(prevMonth);
10310 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
10312 nextMonth = nextMonth.valueOf();
10314 var fillMonths = false;
10316 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
10318 while(prevMonth.valueOf() < nextMonth) {
10321 if (prevMonth.getUTCDay() === this.weekStart) {
10323 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
10331 if(this.calendarWeeks){
10332 // ISO 8601: First week contains first thursday.
10333 // ISO also states week starts on Monday, but we can be more abstract here.
10335 // Start of current week: based on weekstart/current date
10336 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
10337 // Thursday of this week
10338 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
10339 // First Thursday of year, year from thursday
10340 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
10341 // Calendar week: ms between thursdays, div ms per day, div 7 days
10342 calWeek = (th - yth) / 864e5 / 7 + 1;
10344 fillMonths.cn.push({
10352 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
10354 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
10357 if (this.todayHighlight &&
10358 prevMonth.getUTCFullYear() == today.getFullYear() &&
10359 prevMonth.getUTCMonth() == today.getMonth() &&
10360 prevMonth.getUTCDate() == today.getDate()) {
10361 clsName += ' today';
10364 if (currentDate && prevMonth.valueOf() === currentDate) {
10365 clsName += ' active';
10368 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
10369 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
10370 clsName += ' disabled';
10373 fillMonths.cn.push({
10375 cls: 'day ' + clsName,
10376 html: prevMonth.getDate()
10379 prevMonth.setDate(prevMonth.getDate()+1);
10382 var currentYear = this.date && this.date.getUTCFullYear();
10383 var currentMonth = this.date && this.date.getUTCMonth();
10385 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
10387 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
10388 v.removeClass('active');
10390 if(currentYear === year && k === currentMonth){
10391 v.addClass('active');
10394 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
10395 v.addClass('disabled');
10401 year = parseInt(year/10, 10) * 10;
10403 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
10405 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
10408 for (var i = -1; i < 11; i++) {
10409 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
10411 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
10419 showMode: function(dir) {
10421 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
10423 Roo.each(this.picker().select('>div',true).elements, function(v){
10424 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10427 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
10432 if(this.isInline) return;
10434 this.picker().removeClass(['bottom', 'top']);
10436 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
10438 * place to the top of element!
10442 this.picker().addClass('top');
10443 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10448 this.picker().addClass('bottom');
10450 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10453 parseDate : function(value){
10454 if(!value || value instanceof Date){
10457 var v = Date.parseDate(value, this.format);
10458 if (!v && this.useIso) {
10459 v = Date.parseDate(value, 'Y-m-d');
10461 if(!v && this.altFormats){
10462 if(!this.altFormatsArray){
10463 this.altFormatsArray = this.altFormats.split("|");
10465 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
10466 v = Date.parseDate(value, this.altFormatsArray[i]);
10472 formatDate : function(date, fmt){
10473 return (!date || !(date instanceof Date)) ?
10474 date : date.dateFormat(fmt || this.format);
10477 onFocus : function()
10479 Roo.bootstrap.DateField.superclass.onFocus.call(this);
10483 onBlur : function()
10485 Roo.bootstrap.DateField.superclass.onBlur.call(this);
10491 this.picker().show();
10498 if(this.isInline) return;
10499 this.picker().hide();
10500 this.viewMode = this.startViewMode;
10505 onMousedown: function(e){
10506 e.stopPropagation();
10507 e.preventDefault();
10510 keyup: function(e){
10511 Roo.bootstrap.DateField.superclass.keyup.call(this);
10516 fireKey: function(e){
10517 if (!this.picker().isVisible()){
10518 if (e.keyCode == 27) // allow escape to hide and re-show picker
10522 var dateChanged = false,
10524 newDate, newViewDate;
10528 e.preventDefault();
10532 if (!this.keyboardNavigation) break;
10533 dir = e.keyCode == 37 ? -1 : 1;
10536 newDate = this.moveYear(this.date, dir);
10537 newViewDate = this.moveYear(this.viewDate, dir);
10538 } else if (e.shiftKey){
10539 newDate = this.moveMonth(this.date, dir);
10540 newViewDate = this.moveMonth(this.viewDate, dir);
10542 newDate = new Date(this.date);
10543 newDate.setUTCDate(this.date.getUTCDate() + dir);
10544 newViewDate = new Date(this.viewDate);
10545 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
10547 if (this.dateWithinRange(newDate)){
10548 this.date = newDate;
10549 this.viewDate = newViewDate;
10550 this.setValue(this.formatDate(this.date));
10552 e.preventDefault();
10553 dateChanged = true;
10558 if (!this.keyboardNavigation) break;
10559 dir = e.keyCode == 38 ? -1 : 1;
10561 newDate = this.moveYear(this.date, dir);
10562 newViewDate = this.moveYear(this.viewDate, dir);
10563 } else if (e.shiftKey){
10564 newDate = this.moveMonth(this.date, dir);
10565 newViewDate = this.moveMonth(this.viewDate, dir);
10567 newDate = new Date(this.date);
10568 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
10569 newViewDate = new Date(this.viewDate);
10570 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
10572 if (this.dateWithinRange(newDate)){
10573 this.date = newDate;
10574 this.viewDate = newViewDate;
10575 this.setValue(this.formatDate(this.date));
10577 e.preventDefault();
10578 dateChanged = true;
10582 this.setValue(this.formatDate(this.date));
10584 e.preventDefault();
10587 this.setValue(this.formatDate(this.date));
10594 onClick: function(e) {
10595 e.stopPropagation();
10596 e.preventDefault();
10598 var target = e.getTarget();
10600 if(target.nodeName.toLowerCase() === 'i'){
10601 target = Roo.get(target).dom.parentNode;
10604 var nodeName = target.nodeName;
10605 var className = target.className;
10606 var html = target.innerHTML;
10608 switch(nodeName.toLowerCase()) {
10610 switch(className) {
10616 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
10617 switch(this.viewMode){
10619 this.viewDate = this.moveMonth(this.viewDate, dir);
10623 this.viewDate = this.moveYear(this.viewDate, dir);
10629 var date = new Date();
10630 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
10632 this.setValue(this.formatDate(this.date));
10638 if (className.indexOf('disabled') === -1) {
10639 this.viewDate.setUTCDate(1);
10640 if (className.indexOf('month') !== -1) {
10641 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
10643 var year = parseInt(html, 10) || 0;
10644 this.viewDate.setUTCFullYear(year);
10653 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
10654 var day = parseInt(html, 10) || 1;
10655 var year = this.viewDate.getUTCFullYear(),
10656 month = this.viewDate.getUTCMonth();
10658 if (className.indexOf('old') !== -1) {
10665 } else if (className.indexOf('new') !== -1) {
10673 this.date = this.UTCDate(year, month, day,0,0,0,0);
10674 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
10676 this.setValue(this.formatDate(this.date));
10683 setStartDate: function(startDate){
10684 this.startDate = startDate || -Infinity;
10685 if (this.startDate !== -Infinity) {
10686 this.startDate = this.parseDate(this.startDate);
10689 this.updateNavArrows();
10692 setEndDate: function(endDate){
10693 this.endDate = endDate || Infinity;
10694 if (this.endDate !== Infinity) {
10695 this.endDate = this.parseDate(this.endDate);
10698 this.updateNavArrows();
10701 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
10702 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
10703 if (typeof(this.daysOfWeekDisabled) !== 'object') {
10704 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
10706 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
10707 return parseInt(d, 10);
10710 this.updateNavArrows();
10713 updateNavArrows: function() {
10714 var d = new Date(this.viewDate),
10715 year = d.getUTCFullYear(),
10716 month = d.getUTCMonth();
10718 Roo.each(this.picker().select('.prev', true).elements, function(v){
10720 switch (this.viewMode) {
10723 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
10729 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
10736 Roo.each(this.picker().select('.next', true).elements, function(v){
10738 switch (this.viewMode) {
10741 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
10747 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
10755 moveMonth: function(date, dir){
10756 if (!dir) return date;
10757 var new_date = new Date(date.valueOf()),
10758 day = new_date.getUTCDate(),
10759 month = new_date.getUTCMonth(),
10760 mag = Math.abs(dir),
10762 dir = dir > 0 ? 1 : -1;
10765 // If going back one month, make sure month is not current month
10766 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
10768 return new_date.getUTCMonth() == month;
10770 // If going forward one month, make sure month is as expected
10771 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
10773 return new_date.getUTCMonth() != new_month;
10775 new_month = month + dir;
10776 new_date.setUTCMonth(new_month);
10777 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
10778 if (new_month < 0 || new_month > 11)
10779 new_month = (new_month + 12) % 12;
10781 // For magnitudes >1, move one month at a time...
10782 for (var i=0; i<mag; i++)
10783 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
10784 new_date = this.moveMonth(new_date, dir);
10785 // ...then reset the day, keeping it in the new month
10786 new_month = new_date.getUTCMonth();
10787 new_date.setUTCDate(day);
10789 return new_month != new_date.getUTCMonth();
10792 // Common date-resetting loop -- if date is beyond end of month, make it
10795 new_date.setUTCDate(--day);
10796 new_date.setUTCMonth(new_month);
10801 moveYear: function(date, dir){
10802 return this.moveMonth(date, dir*12);
10805 dateWithinRange: function(date){
10806 return date >= this.startDate && date <= this.endDate;
10810 remove: function() {
10811 this.picker().remove();
10816 Roo.apply(Roo.bootstrap.DateField, {
10827 html: '<i class="icon-arrow-left"/>'
10837 html: '<i class="icon-arrow-right"/>'
10879 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
10880 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
10881 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
10882 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
10883 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
10896 navFnc: 'FullYear',
10901 navFnc: 'FullYear',
10906 Roo.apply(Roo.bootstrap.DateField, {
10910 cls: 'datepicker dropdown-menu',
10914 cls: 'datepicker-days',
10918 cls: 'table-condensed',
10920 Roo.bootstrap.DateField.head,
10924 Roo.bootstrap.DateField.footer
10931 cls: 'datepicker-months',
10935 cls: 'table-condensed',
10937 Roo.bootstrap.DateField.head,
10938 Roo.bootstrap.DateField.content,
10939 Roo.bootstrap.DateField.footer
10946 cls: 'datepicker-years',
10950 cls: 'table-condensed',
10952 Roo.bootstrap.DateField.head,
10953 Roo.bootstrap.DateField.content,
10954 Roo.bootstrap.DateField.footer
10973 * @class Roo.bootstrap.CheckBox
10974 * @extends Roo.bootstrap.Input
10975 * Bootstrap CheckBox class
10977 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
10978 * @cfg {String} boxLabel The text that appears beside the checkbox
10979 * @cfg {Boolean} checked initnal the element
10982 * Create a new CheckBox
10983 * @param {Object} config The config object
10986 Roo.bootstrap.CheckBox = function(config){
10987 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
10992 * Fires when the element is checked or unchecked.
10993 * @param {Roo.bootstrap.CheckBox} this This input
10994 * @param {Boolean} checked The new checked value
11000 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
11002 inputType: 'checkbox',
11008 getAutoCreate : function()
11010 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11016 cfg.cls = 'form-group' //input-group
11021 type : this.inputType,
11022 value : (!this.checked) ? this.valueOff : this.value,
11024 placeholder : this.placeholder || ''
11028 if (this.disabled) {
11029 input.disabled=true;
11033 input.checked = this.checked;
11037 input.name = this.name;
11041 input.cls += ' input-' + this.size;
11045 ['xs','sm','md','lg'].map(function(size){
11046 if (settings[size]) {
11047 cfg.cls += ' col-' + size + '-' + settings[size];
11051 var inputblock = input;
11053 if (this.before || this.after) {
11056 cls : 'input-group',
11060 inputblock.cn.push({
11062 cls : 'input-group-addon',
11066 inputblock.cn.push(input);
11068 inputblock.cn.push({
11070 cls : 'input-group-addon',
11077 if (align ==='left' && this.fieldLabel.length) {
11078 Roo.log("left and has label");
11084 cls : 'control-label col-md-' + this.labelWidth,
11085 html : this.fieldLabel
11089 cls : "col-md-" + (12 - this.labelWidth),
11096 } else if ( this.fieldLabel.length) {
11103 cls: 'control-label box-input-label',
11104 //cls : 'input-group-addon',
11105 html : this.fieldLabel
11115 Roo.log(" no label && no align");
11130 html: this.boxLabel
11139 * return the real input element.
11141 inputEl: function ()
11143 return this.el.select('input.form-box',true).first();
11146 initEvents : function()
11148 Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
11150 this.inputEl().on('click', this.onClick, this);
11154 onClick : function()
11156 this.setChecked(!this.checked);
11159 setChecked : function(state,suppressEvent)
11161 this.checked = state;
11163 if(suppressEvent !== true){
11164 this.fireEvent('check', this, state);
11167 this.inputEl().dom.value = state ? this.value : this.valueOff;
11181 * @class Roo.bootstrap.Radio
11182 * @extends Roo.bootstrap.CheckBox
11183 * Bootstrap Radio class
11186 * Create a new Radio
11187 * @param {Object} config The config object
11190 Roo.bootstrap.Radio = function(config){
11191 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
11195 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
11197 inputType: 'radio',
11199 getAutoCreate : function()
11201 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11207 cfg.cls = 'form-group' //input-group
11212 type : this.inputType,
11213 value : (!this.checked) ? this.valueOff : this.value,
11215 placeholder : this.placeholder || ''
11219 if (this.disabled) {
11220 input.disabled=true;
11224 input.checked = this.checked;
11228 input.name = this.name;
11232 input.cls += ' input-' + this.size;
11236 ['xs','sm','md','lg'].map(function(size){
11237 if (settings[size]) {
11238 cfg.cls += ' col-' + size + '-' + settings[size];
11242 var inputblock = input;
11244 if (this.before || this.after) {
11247 cls : 'input-group',
11251 inputblock.cn.push({
11253 cls : 'input-group-addon',
11257 inputblock.cn.push(input);
11259 inputblock.cn.push({
11261 cls : 'input-group-addon',
11268 if (align ==='left' && this.fieldLabel.length) {
11269 Roo.log("left and has label");
11275 cls : 'control-label col-md-' + this.labelWidth,
11276 html : this.fieldLabel
11280 cls : "col-md-" + (12 - this.labelWidth),
11287 } else if ( this.fieldLabel.length) {
11294 cls: 'control-label box-input-label',
11295 //cls : 'input-group-addon',
11296 html : this.fieldLabel
11306 Roo.log(" no label && no align");
11321 html: this.boxLabel
11329 onClick : function()
11331 this.setChecked(true);
11334 setChecked : function(state,suppressEvent)
11336 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
11340 this.checked = state;
11342 if(suppressEvent !== true){
11343 this.fireEvent('check', this, state);
11346 this.inputEl().dom.value = state ? this.value : this.valueOff;
11350 getGroupValue : function()
11352 if(typeof(this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true)) == 'undefined'){
11356 return this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true).value;
11360 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
11361 * @return {Mixed} value The field value
11363 getValue : function(){
11364 return this.getGroupValue();
11378 * @class Roo.bootstrap.HtmlEditor
11379 * @extends Roo.bootstrap.Component
11380 * Bootstrap HtmlEditor class
11383 * Create a new HtmlEditor
11384 * @param {Object} config The config object
11387 Roo.bootstrap.HtmlEditor = function(config){
11388 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
11393 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.Component, {
11395 getAutoCreate : function()
11399 // var toolbar = new Roo.bootstrap.ButtonGroup({
11403 // new Roo.bootstrap.Button({
11416 * @class Roo.bootstrap.Table.AbstractSelectionModel
11417 * @extends Roo.util.Observable
11418 * Abstract base class for grid SelectionModels. It provides the interface that should be
11419 * implemented by descendant classes. This class should not be directly instantiated.
11422 Roo.bootstrap.Table.AbstractSelectionModel = function(){
11423 this.locked = false;
11424 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
11428 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
11429 /** @ignore Called by the grid automatically. Do not call directly. */
11430 init : function(grid){
11436 * Locks the selections.
11439 this.locked = true;
11443 * Unlocks the selections.
11445 unlock : function(){
11446 this.locked = false;
11450 * Returns true if the selections are locked.
11451 * @return {Boolean}
11453 isLocked : function(){
11454 return this.locked;
11458 * @class Roo.bootstrap.Table.ColumnModel
11459 * @extends Roo.util.Observable
11460 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
11461 * the columns in the table.
11464 * @param {Object} config An Array of column config objects. See this class's
11465 * config objects for details.
11467 Roo.bootstrap.Table.ColumnModel = function(config){
11469 * The config passed into the constructor
11471 this.config = config;
11474 // if no id, create one
11475 // if the column does not have a dataIndex mapping,
11476 // map it to the order it is in the config
11477 for(var i = 0, len = config.length; i < len; i++){
11479 if(typeof c.dataIndex == "undefined"){
11482 if(typeof c.renderer == "string"){
11483 c.renderer = Roo.util.Format[c.renderer];
11485 if(typeof c.id == "undefined"){
11488 // if(c.editor && c.editor.xtype){
11489 // c.editor = Roo.factory(c.editor, Roo.grid);
11491 // if(c.editor && c.editor.isFormField){
11492 // c.editor = new Roo.grid.GridEditor(c.editor);
11495 this.lookup[c.id] = c;
11499 * The width of columns which have no width specified (defaults to 100)
11502 this.defaultWidth = 100;
11505 * Default sortable of columns which have no sortable specified (defaults to false)
11508 this.defaultSortable = false;
11512 * @event widthchange
11513 * Fires when the width of a column changes.
11514 * @param {ColumnModel} this
11515 * @param {Number} columnIndex The column index
11516 * @param {Number} newWidth The new width
11518 "widthchange": true,
11520 * @event headerchange
11521 * Fires when the text of a header changes.
11522 * @param {ColumnModel} this
11523 * @param {Number} columnIndex The column index
11524 * @param {Number} newText The new header text
11526 "headerchange": true,
11528 * @event hiddenchange
11529 * Fires when a column is hidden or "unhidden".
11530 * @param {ColumnModel} this
11531 * @param {Number} columnIndex The column index
11532 * @param {Boolean} hidden true if hidden, false otherwise
11534 "hiddenchange": true,
11536 * @event columnmoved
11537 * Fires when a column is moved.
11538 * @param {ColumnModel} this
11539 * @param {Number} oldIndex
11540 * @param {Number} newIndex
11542 "columnmoved" : true,
11544 * @event columlockchange
11545 * Fires when a column's locked state is changed
11546 * @param {ColumnModel} this
11547 * @param {Number} colIndex
11548 * @param {Boolean} locked true if locked
11550 "columnlockchange" : true
11552 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
11554 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
11556 * @cfg {String} header The header text to display in the Grid view.
11559 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
11560 * {@link Roo.data.Record} definition from which to draw the column's value. If not
11561 * specified, the column's index is used as an index into the Record's data Array.
11564 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
11565 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
11568 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
11569 * Defaults to the value of the {@link #defaultSortable} property.
11570 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
11573 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
11576 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
11579 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
11582 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
11585 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
11586 * given the cell's data value. See {@link #setRenderer}. If not specified, the
11587 * default renderer uses the raw data value.
11590 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
11594 * Returns the id of the column at the specified index.
11595 * @param {Number} index The column index
11596 * @return {String} the id
11598 getColumnId : function(index){
11599 return this.config[index].id;
11603 * Returns the column for a specified id.
11604 * @param {String} id The column id
11605 * @return {Object} the column
11607 getColumnById : function(id){
11608 return this.lookup[id];
11613 * Returns the column for a specified dataIndex.
11614 * @param {String} dataIndex The column dataIndex
11615 * @return {Object|Boolean} the column or false if not found
11617 getColumnByDataIndex: function(dataIndex){
11618 var index = this.findColumnIndex(dataIndex);
11619 return index > -1 ? this.config[index] : false;
11623 * Returns the index for a specified column id.
11624 * @param {String} id The column id
11625 * @return {Number} the index, or -1 if not found
11627 getIndexById : function(id){
11628 for(var i = 0, len = this.config.length; i < len; i++){
11629 if(this.config[i].id == id){
11637 * Returns the index for a specified column dataIndex.
11638 * @param {String} dataIndex The column dataIndex
11639 * @return {Number} the index, or -1 if not found
11642 findColumnIndex : function(dataIndex){
11643 for(var i = 0, len = this.config.length; i < len; i++){
11644 if(this.config[i].dataIndex == dataIndex){
11652 moveColumn : function(oldIndex, newIndex){
11653 var c = this.config[oldIndex];
11654 this.config.splice(oldIndex, 1);
11655 this.config.splice(newIndex, 0, c);
11656 this.dataMap = null;
11657 this.fireEvent("columnmoved", this, oldIndex, newIndex);
11660 isLocked : function(colIndex){
11661 return this.config[colIndex].locked === true;
11664 setLocked : function(colIndex, value, suppressEvent){
11665 if(this.isLocked(colIndex) == value){
11668 this.config[colIndex].locked = value;
11669 if(!suppressEvent){
11670 this.fireEvent("columnlockchange", this, colIndex, value);
11674 getTotalLockedWidth : function(){
11675 var totalWidth = 0;
11676 for(var i = 0; i < this.config.length; i++){
11677 if(this.isLocked(i) && !this.isHidden(i)){
11678 this.totalWidth += this.getColumnWidth(i);
11684 getLockedCount : function(){
11685 for(var i = 0, len = this.config.length; i < len; i++){
11686 if(!this.isLocked(i)){
11693 * Returns the number of columns.
11696 getColumnCount : function(visibleOnly){
11697 if(visibleOnly === true){
11699 for(var i = 0, len = this.config.length; i < len; i++){
11700 if(!this.isHidden(i)){
11706 return this.config.length;
11710 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
11711 * @param {Function} fn
11712 * @param {Object} scope (optional)
11713 * @return {Array} result
11715 getColumnsBy : function(fn, scope){
11717 for(var i = 0, len = this.config.length; i < len; i++){
11718 var c = this.config[i];
11719 if(fn.call(scope||this, c, i) === true){
11727 * Returns true if the specified column is sortable.
11728 * @param {Number} col The column index
11729 * @return {Boolean}
11731 isSortable : function(col){
11732 if(typeof this.config[col].sortable == "undefined"){
11733 return this.defaultSortable;
11735 return this.config[col].sortable;
11739 * Returns the rendering (formatting) function defined for the column.
11740 * @param {Number} col The column index.
11741 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
11743 getRenderer : function(col){
11744 if(!this.config[col].renderer){
11745 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
11747 return this.config[col].renderer;
11751 * Sets the rendering (formatting) function for a column.
11752 * @param {Number} col The column index
11753 * @param {Function} fn The function to use to process the cell's raw data
11754 * to return HTML markup for the grid view. The render function is called with
11755 * the following parameters:<ul>
11756 * <li>Data value.</li>
11757 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
11758 * <li>css A CSS style string to apply to the table cell.</li>
11759 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
11760 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
11761 * <li>Row index</li>
11762 * <li>Column index</li>
11763 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
11765 setRenderer : function(col, fn){
11766 this.config[col].renderer = fn;
11770 * Returns the width for the specified column.
11771 * @param {Number} col The column index
11774 getColumnWidth : function(col){
11775 return this.config[col].width * 1 || this.defaultWidth;
11779 * Sets the width for a column.
11780 * @param {Number} col The column index
11781 * @param {Number} width The new width
11783 setColumnWidth : function(col, width, suppressEvent){
11784 this.config[col].width = width;
11785 this.totalWidth = null;
11786 if(!suppressEvent){
11787 this.fireEvent("widthchange", this, col, width);
11792 * Returns the total width of all columns.
11793 * @param {Boolean} includeHidden True to include hidden column widths
11796 getTotalWidth : function(includeHidden){
11797 if(!this.totalWidth){
11798 this.totalWidth = 0;
11799 for(var i = 0, len = this.config.length; i < len; i++){
11800 if(includeHidden || !this.isHidden(i)){
11801 this.totalWidth += this.getColumnWidth(i);
11805 return this.totalWidth;
11809 * Returns the header for the specified column.
11810 * @param {Number} col The column index
11813 getColumnHeader : function(col){
11814 return this.config[col].header;
11818 * Sets the header for a column.
11819 * @param {Number} col The column index
11820 * @param {String} header The new header
11822 setColumnHeader : function(col, header){
11823 this.config[col].header = header;
11824 this.fireEvent("headerchange", this, col, header);
11828 * Returns the tooltip for the specified column.
11829 * @param {Number} col The column index
11832 getColumnTooltip : function(col){
11833 return this.config[col].tooltip;
11836 * Sets the tooltip for a column.
11837 * @param {Number} col The column index
11838 * @param {String} tooltip The new tooltip
11840 setColumnTooltip : function(col, tooltip){
11841 this.config[col].tooltip = tooltip;
11845 * Returns the dataIndex for the specified column.
11846 * @param {Number} col The column index
11849 getDataIndex : function(col){
11850 return this.config[col].dataIndex;
11854 * Sets the dataIndex for a column.
11855 * @param {Number} col The column index
11856 * @param {Number} dataIndex The new dataIndex
11858 setDataIndex : function(col, dataIndex){
11859 this.config[col].dataIndex = dataIndex;
11865 * Returns true if the cell is editable.
11866 * @param {Number} colIndex The column index
11867 * @param {Number} rowIndex The row index
11868 * @return {Boolean}
11870 isCellEditable : function(colIndex, rowIndex){
11871 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
11875 * Returns the editor defined for the cell/column.
11876 * return false or null to disable editing.
11877 * @param {Number} colIndex The column index
11878 * @param {Number} rowIndex The row index
11881 getCellEditor : function(colIndex, rowIndex){
11882 return this.config[colIndex].editor;
11886 * Sets if a column is editable.
11887 * @param {Number} col The column index
11888 * @param {Boolean} editable True if the column is editable
11890 setEditable : function(col, editable){
11891 this.config[col].editable = editable;
11896 * Returns true if the column is hidden.
11897 * @param {Number} colIndex The column index
11898 * @return {Boolean}
11900 isHidden : function(colIndex){
11901 return this.config[colIndex].hidden;
11906 * Returns true if the column width cannot be changed
11908 isFixed : function(colIndex){
11909 return this.config[colIndex].fixed;
11913 * Returns true if the column can be resized
11914 * @return {Boolean}
11916 isResizable : function(colIndex){
11917 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
11920 * Sets if a column is hidden.
11921 * @param {Number} colIndex The column index
11922 * @param {Boolean} hidden True if the column is hidden
11924 setHidden : function(colIndex, hidden){
11925 this.config[colIndex].hidden = hidden;
11926 this.totalWidth = null;
11927 this.fireEvent("hiddenchange", this, colIndex, hidden);
11931 * Sets the editor for a column.
11932 * @param {Number} col The column index
11933 * @param {Object} editor The editor object
11935 setEditor : function(col, editor){
11936 this.config[col].editor = editor;
11940 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
11941 if(typeof value == "string" && value.length < 1){
11947 // Alias for backwards compatibility
11948 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
11951 * @extends Roo.bootstrap.Table.AbstractSelectionModel
11952 * @class Roo.bootstrap.Table.RowSelectionModel
11953 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
11954 * It supports multiple selections and keyboard selection/navigation.
11956 * @param {Object} config
11959 Roo.bootstrap.Table.RowSelectionModel = function(config){
11960 Roo.apply(this, config);
11961 this.selections = new Roo.util.MixedCollection(false, function(o){
11966 this.lastActive = false;
11970 * @event selectionchange
11971 * Fires when the selection changes
11972 * @param {SelectionModel} this
11974 "selectionchange" : true,
11976 * @event afterselectionchange
11977 * Fires after the selection changes (eg. by key press or clicking)
11978 * @param {SelectionModel} this
11980 "afterselectionchange" : true,
11982 * @event beforerowselect
11983 * Fires when a row is selected being selected, return false to cancel.
11984 * @param {SelectionModel} this
11985 * @param {Number} rowIndex The selected index
11986 * @param {Boolean} keepExisting False if other selections will be cleared
11988 "beforerowselect" : true,
11991 * Fires when a row is selected.
11992 * @param {SelectionModel} this
11993 * @param {Number} rowIndex The selected index
11994 * @param {Roo.data.Record} r The record
11996 "rowselect" : true,
11998 * @event rowdeselect
11999 * Fires when a row is deselected.
12000 * @param {SelectionModel} this
12001 * @param {Number} rowIndex The selected index
12003 "rowdeselect" : true
12005 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
12006 this.locked = false;
12009 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
12011 * @cfg {Boolean} singleSelect
12012 * True to allow selection of only one row at a time (defaults to false)
12014 singleSelect : false,
12017 initEvents : function(){
12019 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
12020 this.grid.on("mousedown", this.handleMouseDown, this);
12021 }else{ // allow click to work like normal
12022 this.grid.on("rowclick", this.handleDragableRowClick, this);
12025 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
12026 "up" : function(e){
12028 this.selectPrevious(e.shiftKey);
12029 }else if(this.last !== false && this.lastActive !== false){
12030 var last = this.last;
12031 this.selectRange(this.last, this.lastActive-1);
12032 this.grid.getView().focusRow(this.lastActive);
12033 if(last !== false){
12037 this.selectFirstRow();
12039 this.fireEvent("afterselectionchange", this);
12041 "down" : function(e){
12043 this.selectNext(e.shiftKey);
12044 }else if(this.last !== false && this.lastActive !== false){
12045 var last = this.last;
12046 this.selectRange(this.last, this.lastActive+1);
12047 this.grid.getView().focusRow(this.lastActive);
12048 if(last !== false){
12052 this.selectFirstRow();
12054 this.fireEvent("afterselectionchange", this);
12059 var view = this.grid.view;
12060 view.on("refresh", this.onRefresh, this);
12061 view.on("rowupdated", this.onRowUpdated, this);
12062 view.on("rowremoved", this.onRemove, this);
12066 onRefresh : function(){
12067 var ds = this.grid.dataSource, i, v = this.grid.view;
12068 var s = this.selections;
12069 s.each(function(r){
12070 if((i = ds.indexOfId(r.id)) != -1){
12079 onRemove : function(v, index, r){
12080 this.selections.remove(r);
12084 onRowUpdated : function(v, index, r){
12085 if(this.isSelected(r)){
12086 v.onRowSelect(index);
12092 * @param {Array} records The records to select
12093 * @param {Boolean} keepExisting (optional) True to keep existing selections
12095 selectRecords : function(records, keepExisting){
12097 this.clearSelections();
12099 var ds = this.grid.dataSource;
12100 for(var i = 0, len = records.length; i < len; i++){
12101 this.selectRow(ds.indexOf(records[i]), true);
12106 * Gets the number of selected rows.
12109 getCount : function(){
12110 return this.selections.length;
12114 * Selects the first row in the grid.
12116 selectFirstRow : function(){
12121 * Select the last row.
12122 * @param {Boolean} keepExisting (optional) True to keep existing selections
12124 selectLastRow : function(keepExisting){
12125 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
12129 * Selects the row immediately following the last selected row.
12130 * @param {Boolean} keepExisting (optional) True to keep existing selections
12132 selectNext : function(keepExisting){
12133 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
12134 this.selectRow(this.last+1, keepExisting);
12135 this.grid.getView().focusRow(this.last);
12140 * Selects the row that precedes the last selected row.
12141 * @param {Boolean} keepExisting (optional) True to keep existing selections
12143 selectPrevious : function(keepExisting){
12145 this.selectRow(this.last-1, keepExisting);
12146 this.grid.getView().focusRow(this.last);
12151 * Returns the selected records
12152 * @return {Array} Array of selected records
12154 getSelections : function(){
12155 return [].concat(this.selections.items);
12159 * Returns the first selected record.
12162 getSelected : function(){
12163 return this.selections.itemAt(0);
12168 * Clears all selections.
12170 clearSelections : function(fast){
12171 if(this.locked) return;
12173 var ds = this.grid.dataSource;
12174 var s = this.selections;
12175 s.each(function(r){
12176 this.deselectRow(ds.indexOfId(r.id));
12180 this.selections.clear();
12187 * Selects all rows.
12189 selectAll : function(){
12190 if(this.locked) return;
12191 this.selections.clear();
12192 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
12193 this.selectRow(i, true);
12198 * Returns True if there is a selection.
12199 * @return {Boolean}
12201 hasSelection : function(){
12202 return this.selections.length > 0;
12206 * Returns True if the specified row is selected.
12207 * @param {Number/Record} record The record or index of the record to check
12208 * @return {Boolean}
12210 isSelected : function(index){
12211 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
12212 return (r && this.selections.key(r.id) ? true : false);
12216 * Returns True if the specified record id is selected.
12217 * @param {String} id The id of record to check
12218 * @return {Boolean}
12220 isIdSelected : function(id){
12221 return (this.selections.key(id) ? true : false);
12225 handleMouseDown : function(e, t){
12226 var view = this.grid.getView(), rowIndex;
12227 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
12230 if(e.shiftKey && this.last !== false){
12231 var last = this.last;
12232 this.selectRange(last, rowIndex, e.ctrlKey);
12233 this.last = last; // reset the last
12234 view.focusRow(rowIndex);
12236 var isSelected = this.isSelected(rowIndex);
12237 if(e.button !== 0 && isSelected){
12238 view.focusRow(rowIndex);
12239 }else if(e.ctrlKey && isSelected){
12240 this.deselectRow(rowIndex);
12241 }else if(!isSelected){
12242 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
12243 view.focusRow(rowIndex);
12246 this.fireEvent("afterselectionchange", this);
12249 handleDragableRowClick : function(grid, rowIndex, e)
12251 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
12252 this.selectRow(rowIndex, false);
12253 grid.view.focusRow(rowIndex);
12254 this.fireEvent("afterselectionchange", this);
12259 * Selects multiple rows.
12260 * @param {Array} rows Array of the indexes of the row to select
12261 * @param {Boolean} keepExisting (optional) True to keep existing selections
12263 selectRows : function(rows, keepExisting){
12265 this.clearSelections();
12267 for(var i = 0, len = rows.length; i < len; i++){
12268 this.selectRow(rows[i], true);
12273 * Selects a range of rows. All rows in between startRow and endRow are also selected.
12274 * @param {Number} startRow The index of the first row in the range
12275 * @param {Number} endRow The index of the last row in the range
12276 * @param {Boolean} keepExisting (optional) True to retain existing selections
12278 selectRange : function(startRow, endRow, keepExisting){
12279 if(this.locked) return;
12281 this.clearSelections();
12283 if(startRow <= endRow){
12284 for(var i = startRow; i <= endRow; i++){
12285 this.selectRow(i, true);
12288 for(var i = startRow; i >= endRow; i--){
12289 this.selectRow(i, true);
12295 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
12296 * @param {Number} startRow The index of the first row in the range
12297 * @param {Number} endRow The index of the last row in the range
12299 deselectRange : function(startRow, endRow, preventViewNotify){
12300 if(this.locked) return;
12301 for(var i = startRow; i <= endRow; i++){
12302 this.deselectRow(i, preventViewNotify);
12308 * @param {Number} row The index of the row to select
12309 * @param {Boolean} keepExisting (optional) True to keep existing selections
12311 selectRow : function(index, keepExisting, preventViewNotify){
12312 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
12313 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
12314 if(!keepExisting || this.singleSelect){
12315 this.clearSelections();
12317 var r = this.grid.dataSource.getAt(index);
12318 this.selections.add(r);
12319 this.last = this.lastActive = index;
12320 if(!preventViewNotify){
12321 this.grid.getView().onRowSelect(index);
12323 this.fireEvent("rowselect", this, index, r);
12324 this.fireEvent("selectionchange", this);
12330 * @param {Number} row The index of the row to deselect
12332 deselectRow : function(index, preventViewNotify){
12333 if(this.locked) return;
12334 if(this.last == index){
12337 if(this.lastActive == index){
12338 this.lastActive = false;
12340 var r = this.grid.dataSource.getAt(index);
12341 this.selections.remove(r);
12342 if(!preventViewNotify){
12343 this.grid.getView().onRowDeselect(index);
12345 this.fireEvent("rowdeselect", this, index);
12346 this.fireEvent("selectionchange", this);
12350 restoreLast : function(){
12352 this.last = this._last;
12357 acceptsNav : function(row, col, cm){
12358 return !cm.isHidden(col) && cm.isCellEditable(col, row);
12362 onEditorKey : function(field, e){
12363 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
12368 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
12370 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
12372 }else if(k == e.ENTER && !e.ctrlKey){
12376 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
12378 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
12380 }else if(k == e.ESC){
12384 g.startEditing(newCell[0], newCell[1]);