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 (['tabs','pills'].indexOf(this.parent().type)!==-1) {
1949 this.onTabsClick(e);
1952 this.fireEvent('click', this, e);
1955 onTabsClick : function(e)
1957 Roo.each(this.parent().el.select('.active',true).elements, function(v){
1958 v.removeClass('active');
1961 this.el.addClass('active');
1963 if(this.href && this.href.substring(0,1) == '#'){
1964 var tab = Roo.select('[tabId=' + this.href + ']', true).first();
1966 Roo.each(tab.findParent('.tab-content', 0, true).select('.active', true).elements, function(v){
1967 v.removeClass('active');
1970 tab.addClass('active');
1985 * @class Roo.bootstrap.Row
1986 * @extends Roo.bootstrap.Component
1987 * Bootstrap Row class (contains columns...)
1991 * @param {Object} config The config object
1994 Roo.bootstrap.Row = function(config){
1995 Roo.bootstrap.Row.superclass.constructor.call(this, config);
1998 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
2000 getAutoCreate : function(){
2019 * @class Roo.bootstrap.Element
2020 * @extends Roo.bootstrap.Component
2021 * Bootstrap Element class
2022 * @cfg {String} html contents of the element
2023 * @cfg {String} tag tag of the element
2024 * @cfg {String} cls class of the element
2027 * Create a new Element
2028 * @param {Object} config The config object
2031 Roo.bootstrap.Element = function(config){
2032 Roo.bootstrap.Element.superclass.constructor.call(this, config);
2035 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
2042 getAutoCreate : function(){
2067 * @class Roo.bootstrap.Pagination
2068 * @extends Roo.bootstrap.Component
2069 * Bootstrap Pagination class
2070 * @cfg {String} size xs | sm | md | lg
2071 * @cfg {Boolean} inverse false | true
2074 * Create a new Pagination
2075 * @param {Object} config The config object
2078 Roo.bootstrap.Pagination = function(config){
2079 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
2082 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
2088 getAutoCreate : function(){
2094 cfg.cls += ' inverse';
2100 cfg.cls += " " + this.cls;
2118 * @class Roo.bootstrap.PaginationItem
2119 * @extends Roo.bootstrap.Component
2120 * Bootstrap PaginationItem class
2121 * @cfg {String} html text
2122 * @cfg {String} href the link
2123 * @cfg {Boolean} preventDefault (true | false) default true
2124 * @cfg {Boolean} active (true | false) default false
2128 * Create a new PaginationItem
2129 * @param {Object} config The config object
2133 Roo.bootstrap.PaginationItem = function(config){
2134 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
2139 * The raw click event for the entire grid.
2140 * @param {Roo.EventObject} e
2146 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
2150 preventDefault: true,
2154 getAutoCreate : function(){
2160 href : this.href ? this.href : '#',
2161 html : this.html ? this.html : ''
2171 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
2177 initEvents: function() {
2179 this.el.on('click', this.onClick, this);
2182 onClick : function(e)
2184 Roo.log('PaginationItem on click ');
2185 if(this.preventDefault){
2189 this.fireEvent('click', this, e);
2205 * @class Roo.bootstrap.Slider
2206 * @extends Roo.bootstrap.Component
2207 * Bootstrap Slider class
2210 * Create a new Slider
2211 * @param {Object} config The config object
2214 Roo.bootstrap.Slider = function(config){
2215 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
2218 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
2220 getAutoCreate : function(){
2224 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
2228 cls: 'ui-slider-handle ui-state-default ui-corner-all'
2246 * @class Roo.bootstrap.Table
2247 * @extends Roo.bootstrap.Component
2248 * Bootstrap Table class
2249 * @cfg {String} cls table class
2250 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
2251 * @cfg {String} bgcolor Specifies the background color for a table
2252 * @cfg {Number} border Specifies whether the table cells should have borders or not
2253 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
2254 * @cfg {Number} cellspacing Specifies the space between cells
2255 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
2256 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
2257 * @cfg {String} sortable Specifies that the table should be sortable
2258 * @cfg {String} summary Specifies a summary of the content of a table
2259 * @cfg {Number} width Specifies the width of a table
2261 * @cfg {boolean} striped Should the rows be alternative striped
2262 * @cfg {boolean} bordered Add borders to the table
2263 * @cfg {boolean} hover Add hover highlighting
2264 * @cfg {boolean} condensed Format condensed
2265 * @cfg {boolean} responsive Format condensed
2271 * Create a new Table
2272 * @param {Object} config The config object
2275 Roo.bootstrap.Table = function(config){
2276 Roo.bootstrap.Table.superclass.constructor.call(this, config);
2279 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
2280 this.sm = this.selModel;
2281 this.sm.xmodule = this.xmodule || false;
2283 if (this.cm && typeof(this.cm.config) == 'undefined') {
2284 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
2285 this.cm = this.colModel;
2286 this.cm.xmodule = this.xmodule || false;
2289 this.store= Roo.factory(this.store, Roo.data);
2290 this.ds = this.store;
2291 this.ds.xmodule = this.xmodule || false;
2296 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
2318 getAutoCreate : function(){
2319 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2327 cfg.cls += ' table-striped';
2330 cfg.cls += ' table-hover';
2332 if (this.bordered) {
2333 cfg.cls += ' table-bordered';
2335 if (this.condensed) {
2336 cfg.cls += ' table-condensed';
2338 if (this.responsive) {
2339 cfg.cls += ' table-responsive';
2346 cfg.cls+= ' ' +this.cls;
2349 // this lot should be simplifed...
2352 cfg.align=this.align;
2355 cfg.bgcolor=this.bgcolor;
2358 cfg.border=this.border;
2360 if (this.cellpadding) {
2361 cfg.cellpadding=this.cellpadding;
2363 if (this.cellspacing) {
2364 cfg.cellspacing=this.cellspacing;
2367 cfg.frame=this.frame;
2370 cfg.rules=this.rules;
2372 if (this.sortable) {
2373 cfg.sortable=this.sortable;
2376 cfg.summary=this.summary;
2379 cfg.width=this.width;
2382 if(this.store && this.cm && this.sm){
2383 cfg.cn = this.initTableGrid();
2389 initTableGrid : function()
2399 initEvents : function()
2401 if(!this.store && !this.cm && !this.sm){
2405 Roo.log('initEvents!!!!');
2409 var colCount = cm.getColumnCount();
2411 var header = this.renderHeaders();
2415 renderHeaders : function()
2432 * @class Roo.bootstrap.TableCell
2433 * @extends Roo.bootstrap.Component
2434 * Bootstrap TableCell class
2435 * @cfg {String} html cell contain text
2436 * @cfg {String} cls cell class
2437 * @cfg {String} tag cell tag (td|th) default td
2438 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
2439 * @cfg {String} align Aligns the content in a cell
2440 * @cfg {String} axis Categorizes cells
2441 * @cfg {String} bgcolor Specifies the background color of a cell
2442 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
2443 * @cfg {Number} colspan Specifies the number of columns a cell should span
2444 * @cfg {String} headers Specifies one or more header cells a cell is related to
2445 * @cfg {Number} height Sets the height of a cell
2446 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
2447 * @cfg {Number} rowspan Sets the number of rows a cell should span
2448 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
2449 * @cfg {String} valign Vertical aligns the content in a cell
2450 * @cfg {Number} width Specifies the width of a cell
2453 * Create a new TableCell
2454 * @param {Object} config The config object
2457 Roo.bootstrap.TableCell = function(config){
2458 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
2461 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
2481 getAutoCreate : function(){
2482 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
2502 cfg.align=this.align
2508 cfg.bgcolor=this.bgcolor
2511 cfg.charoff=this.charoff
2514 cfg.colspan=this.colspan
2517 cfg.headers=this.headers
2520 cfg.height=this.height
2523 cfg.nowrap=this.nowrap
2526 cfg.rowspan=this.rowspan
2529 cfg.scope=this.scope
2532 cfg.valign=this.valign
2535 cfg.width=this.width
2554 * @class Roo.bootstrap.TableRow
2555 * @extends Roo.bootstrap.Component
2556 * Bootstrap TableRow class
2557 * @cfg {String} cls row class
2558 * @cfg {String} align Aligns the content in a table row
2559 * @cfg {String} bgcolor Specifies a background color for a table row
2560 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
2561 * @cfg {String} valign Vertical aligns the content in a table row
2564 * Create a new TableRow
2565 * @param {Object} config The config object
2568 Roo.bootstrap.TableRow = function(config){
2569 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2572 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
2580 getAutoCreate : function(){
2581 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2591 cfg.align = this.align;
2594 cfg.bgcolor = this.bgcolor;
2597 cfg.charoff = this.charoff;
2600 cfg.valign = this.valign;
2618 * @class Roo.bootstrap.TableBody
2619 * @extends Roo.bootstrap.Component
2620 * Bootstrap TableBody class
2621 * @cfg {String} cls element class
2622 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
2623 * @cfg {String} align Aligns the content inside the element
2624 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
2625 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
2628 * Create a new TableBody
2629 * @param {Object} config The config object
2632 Roo.bootstrap.TableBody = function(config){
2633 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
2636 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
2644 getAutoCreate : function(){
2645 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
2659 cfg.align = this.align;
2662 cfg.charoff = this.charoff;
2665 cfg.valign = this.valign;
2672 // initEvents : function()
2679 // this.store = Roo.factory(this.store, Roo.data);
2680 // this.store.on('load', this.onLoad, this);
2682 // this.store.load();
2686 // onLoad: function ()
2688 // this.fireEvent('load', this);
2698 * Ext JS Library 1.1.1
2699 * Copyright(c) 2006-2007, Ext JS, LLC.
2701 * Originally Released Under LGPL - original licence link has changed is not relivant.
2704 * <script type="text/javascript">
2707 // as we use this in bootstrap.
2708 Roo.namespace('Roo.form');
2710 * @class Roo.form.Action
2711 * Internal Class used to handle form actions
2713 * @param {Roo.form.BasicForm} el The form element or its id
2714 * @param {Object} config Configuration options
2719 // define the action interface
2720 Roo.form.Action = function(form, options){
2722 this.options = options || {};
2725 * Client Validation Failed
2728 Roo.form.Action.CLIENT_INVALID = 'client';
2730 * Server Validation Failed
2733 Roo.form.Action.SERVER_INVALID = 'server';
2735 * Connect to Server Failed
2738 Roo.form.Action.CONNECT_FAILURE = 'connect';
2740 * Reading Data from Server Failed
2743 Roo.form.Action.LOAD_FAILURE = 'load';
2745 Roo.form.Action.prototype = {
2747 failureType : undefined,
2748 response : undefined,
2752 run : function(options){
2757 success : function(response){
2762 handleResponse : function(response){
2766 // default connection failure
2767 failure : function(response){
2769 this.response = response;
2770 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2771 this.form.afterAction(this, false);
2774 processResponse : function(response){
2775 this.response = response;
2776 if(!response.responseText){
2779 this.result = this.handleResponse(response);
2783 // utility functions used internally
2784 getUrl : function(appendParams){
2785 var url = this.options.url || this.form.url || this.form.el.dom.action;
2787 var p = this.getParams();
2789 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2795 getMethod : function(){
2796 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2799 getParams : function(){
2800 var bp = this.form.baseParams;
2801 var p = this.options.params;
2803 if(typeof p == "object"){
2804 p = Roo.urlEncode(Roo.applyIf(p, bp));
2805 }else if(typeof p == 'string' && bp){
2806 p += '&' + Roo.urlEncode(bp);
2809 p = Roo.urlEncode(bp);
2814 createCallback : function(){
2816 success: this.success,
2817 failure: this.failure,
2819 timeout: (this.form.timeout*1000),
2820 upload: this.form.fileUpload ? this.success : undefined
2825 Roo.form.Action.Submit = function(form, options){
2826 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
2829 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
2832 haveProgress : false,
2833 uploadComplete : false,
2835 // uploadProgress indicator.
2836 uploadProgress : function()
2838 if (!this.form.progressUrl) {
2842 if (!this.haveProgress) {
2843 Roo.MessageBox.progress("Uploading", "Uploading");
2845 if (this.uploadComplete) {
2846 Roo.MessageBox.hide();
2850 this.haveProgress = true;
2852 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
2854 var c = new Roo.data.Connection();
2856 url : this.form.progressUrl,
2861 success : function(req){
2862 //console.log(data);
2866 rdata = Roo.decode(req.responseText)
2868 Roo.log("Invalid data from server..");
2872 if (!rdata || !rdata.success) {
2874 Roo.MessageBox.alert(Roo.encode(rdata));
2877 var data = rdata.data;
2879 if (this.uploadComplete) {
2880 Roo.MessageBox.hide();
2885 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
2886 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
2889 this.uploadProgress.defer(2000,this);
2892 failure: function(data) {
2893 Roo.log('progress url failed ');
2904 // run get Values on the form, so it syncs any secondary forms.
2905 this.form.getValues();
2907 var o = this.options;
2908 var method = this.getMethod();
2909 var isPost = method == 'POST';
2911 Roo.log(this.form.isValid());
2912 if(o.clientValidation === false || this.form.isValid()){
2914 if (this.form.progressUrl) {
2915 this.form.findField('UPLOAD_IDENTIFIER').setValue(
2916 (new Date() * 1) + '' + Math.random());
2921 Roo.Ajax.request(Roo.apply(this.createCallback(), {
2922 form:this.form.el.dom,
2923 url:this.getUrl(!isPost),
2925 params:isPost ? this.getParams() : null,
2926 isUpload: this.form.fileUpload
2929 this.uploadProgress();
2931 }else if (o.clientValidation !== false){ // client validation failed
2932 this.failureType = Roo.form.Action.CLIENT_INVALID;
2933 this.form.afterAction(this, false);
2937 success : function(response)
2939 this.uploadComplete= true;
2940 if (this.haveProgress) {
2941 Roo.MessageBox.hide();
2945 var result = this.processResponse(response);
2946 if(result === true || result.success){
2947 this.form.afterAction(this, true);
2951 this.form.markInvalid(result.errors);
2952 this.failureType = Roo.form.Action.SERVER_INVALID;
2954 this.form.afterAction(this, false);
2956 failure : function(response)
2958 this.uploadComplete= true;
2959 if (this.haveProgress) {
2960 Roo.MessageBox.hide();
2963 this.response = response;
2964 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2965 this.form.afterAction(this, false);
2968 handleResponse : function(response){
2969 if(this.form.errorReader){
2970 var rs = this.form.errorReader.read(response);
2973 for(var i = 0, len = rs.records.length; i < len; i++) {
2974 var r = rs.records[i];
2978 if(errors.length < 1){
2982 success : rs.success,
2988 ret = Roo.decode(response.responseText);
2992 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
3002 Roo.form.Action.Load = function(form, options){
3003 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
3004 this.reader = this.form.reader;
3007 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
3012 Roo.Ajax.request(Roo.apply(
3013 this.createCallback(), {
3014 method:this.getMethod(),
3015 url:this.getUrl(false),
3016 params:this.getParams()
3020 success : function(response){
3022 var result = this.processResponse(response);
3023 if(result === true || !result.success || !result.data){
3024 this.failureType = Roo.form.Action.LOAD_FAILURE;
3025 this.form.afterAction(this, false);
3028 this.form.clearInvalid();
3029 this.form.setValues(result.data);
3030 this.form.afterAction(this, true);
3033 handleResponse : function(response){
3034 if(this.form.reader){
3035 var rs = this.form.reader.read(response);
3036 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
3038 success : rs.success,
3042 return Roo.decode(response.responseText);
3046 Roo.form.Action.ACTION_TYPES = {
3047 'load' : Roo.form.Action.Load,
3048 'submit' : Roo.form.Action.Submit
3057 * @class Roo.bootstrap.Form
3058 * @extends Roo.bootstrap.Component
3059 * Bootstrap Form class
3060 * @cfg {String} method GET | POST (default POST)
3061 * @cfg {String} labelAlign top | left (default top)
3062 * @cfg {String} align left | right - for navbars
3067 * @param {Object} config The config object
3071 Roo.bootstrap.Form = function(config){
3072 Roo.bootstrap.Form.superclass.constructor.call(this, config);
3075 * @event clientvalidation
3076 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
3077 * @param {Form} this
3078 * @param {Boolean} valid true if the form has passed client-side validation
3080 clientvalidation: true,
3082 * @event beforeaction
3083 * Fires before any action is performed. Return false to cancel the action.
3084 * @param {Form} this
3085 * @param {Action} action The action to be performed
3089 * @event actionfailed
3090 * Fires when an action fails.
3091 * @param {Form} this
3092 * @param {Action} action The action that failed
3094 actionfailed : true,
3096 * @event actioncomplete
3097 * Fires when an action is completed.
3098 * @param {Form} this
3099 * @param {Action} action The action that completed
3101 actioncomplete : true
3106 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
3109 * @cfg {String} method
3110 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
3115 * The URL to use for form actions if one isn't supplied in the action options.
3118 * @cfg {Boolean} fileUpload
3119 * Set to true if this form is a file upload.
3123 * @cfg {Object} baseParams
3124 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
3128 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
3132 * @cfg {Sting} align (left|right) for navbar forms
3137 activeAction : null,
3140 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3141 * element by passing it or its id or mask the form itself by passing in true.
3144 waitMsgTarget : false,
3149 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3150 * element by passing it or its id or mask the form itself by passing in true.
3154 getAutoCreate : function(){
3158 method : this.method || 'POST',
3159 id : this.id || Roo.id(),
3162 if (this.parent().xtype.match(/^Nav/)) {
3163 cfg.cls = 'navbar-form navbar-' + this.align;
3167 if (this.labelAlign == 'left' ) {
3168 cfg.cls += ' form-horizontal';
3174 initEvents : function()
3176 this.el.on('submit', this.onSubmit, this);
3181 onSubmit : function(e){
3186 * Returns true if client-side validation on the form is successful.
3189 isValid : function(){
3190 var items = this.getItems();
3192 items.each(function(f){
3201 * Returns true if any fields in this form have changed since their original load.
3204 isDirty : function(){
3206 var items = this.getItems();
3207 items.each(function(f){
3217 * Performs a predefined action (submit or load) or custom actions you define on this form.
3218 * @param {String} actionName The name of the action type
3219 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
3220 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
3221 * accept other config options):
3223 Property Type Description
3224 ---------------- --------------- ----------------------------------------------------------------------------------
3225 url String The url for the action (defaults to the form's url)
3226 method String The form method to use (defaults to the form's method, or POST if not defined)
3227 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
3228 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
3229 validate the form on the client (defaults to false)
3231 * @return {BasicForm} this
3233 doAction : function(action, options){
3234 if(typeof action == 'string'){
3235 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
3238 if(this.fireEvent('beforeaction', this, action) !== false){
3240 this.beforeAction(action);
3241 action.run.defer(100, action);
3247 beforeAction : function(action){
3248 var o = action.options;
3250 // not really supported yet.. ??
3252 //if(this.waitMsgTarget === true){
3253 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
3254 //}else if(this.waitMsgTarget){
3255 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
3256 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
3258 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
3264 afterAction : function(action, success){
3265 this.activeAction = null;
3266 var o = action.options;
3268 //if(this.waitMsgTarget === true){
3270 //}else if(this.waitMsgTarget){
3271 // this.waitMsgTarget.unmask();
3273 // Roo.MessageBox.updateProgress(1);
3274 // Roo.MessageBox.hide();
3281 Roo.callback(o.success, o.scope, [this, action]);
3282 this.fireEvent('actioncomplete', this, action);
3286 // failure condition..
3287 // we have a scenario where updates need confirming.
3288 // eg. if a locking scenario exists..
3289 // we look for { errors : { needs_confirm : true }} in the response.
3291 (typeof(action.result) != 'undefined') &&
3292 (typeof(action.result.errors) != 'undefined') &&
3293 (typeof(action.result.errors.needs_confirm) != 'undefined')
3296 Roo.log("not supported yet");
3299 Roo.MessageBox.confirm(
3300 "Change requires confirmation",
3301 action.result.errorMsg,
3306 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
3316 Roo.callback(o.failure, o.scope, [this, action]);
3317 // show an error message if no failed handler is set..
3318 if (!this.hasListener('actionfailed')) {
3319 Roo.log("need to add dialog support");
3321 Roo.MessageBox.alert("Error",
3322 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
3323 action.result.errorMsg :
3324 "Saving Failed, please check your entries or try again"
3329 this.fireEvent('actionfailed', this, action);
3334 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
3335 * @param {String} id The value to search for
3338 findField : function(id){
3339 var items = this.getItems();
3340 var field = items.get(id);
3342 items.each(function(f){
3343 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
3350 return field || null;
3353 * Mark fields in this form invalid in bulk.
3354 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
3355 * @return {BasicForm} this
3357 markInvalid : function(errors){
3358 if(errors instanceof Array){
3359 for(var i = 0, len = errors.length; i < len; i++){
3360 var fieldError = errors[i];
3361 var f = this.findField(fieldError.id);
3363 f.markInvalid(fieldError.msg);
3369 if(typeof errors[id] != 'function' && (field = this.findField(id))){
3370 field.markInvalid(errors[id]);
3374 //Roo.each(this.childForms || [], function (f) {
3375 // f.markInvalid(errors);
3382 * Set values for fields in this form in bulk.
3383 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
3384 * @return {BasicForm} this
3386 setValues : function(values){
3387 if(values instanceof Array){ // array of objects
3388 for(var i = 0, len = values.length; i < len; i++){
3390 var f = this.findField(v.id);
3392 f.setValue(v.value);
3393 if(this.trackResetOnLoad){
3394 f.originalValue = f.getValue();
3398 }else{ // object hash
3401 if(typeof values[id] != 'function' && (field = this.findField(id))){
3403 if (field.setFromData &&
3405 field.displayField &&
3406 // combos' with local stores can
3407 // be queried via setValue()
3408 // to set their value..
3409 (field.store && !field.store.isLocal)
3413 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
3414 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
3415 field.setFromData(sd);
3418 field.setValue(values[id]);
3422 if(this.trackResetOnLoad){
3423 field.originalValue = field.getValue();
3429 //Roo.each(this.childForms || [], function (f) {
3430 // f.setValues(values);
3437 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
3438 * they are returned as an array.
3439 * @param {Boolean} asString
3442 getValues : function(asString){
3443 //if (this.childForms) {
3444 // copy values from the child forms
3445 // Roo.each(this.childForms, function (f) {
3446 // this.setValues(f.getValues());
3452 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
3453 if(asString === true){
3456 return Roo.urlDecode(fs);
3460 * Returns the fields in this form as an object with key/value pairs.
3461 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
3464 getFieldValues : function(with_hidden)
3466 var items = this.getItems();
3468 items.each(function(f){
3472 var v = f.getValue();
3473 if (f.inputType =='radio') {
3474 if (typeof(ret[f.getName()]) == 'undefined') {
3475 ret[f.getName()] = ''; // empty..
3478 if (!f.el.dom.checked) {
3486 // not sure if this supported any more..
3487 if ((typeof(v) == 'object') && f.getRawValue) {
3488 v = f.getRawValue() ; // dates..
3490 // combo boxes where name != hiddenName...
3491 if (f.name != f.getName()) {
3492 ret[f.name] = f.getRawValue();
3494 ret[f.getName()] = v;
3501 * Clears all invalid messages in this form.
3502 * @return {BasicForm} this
3504 clearInvalid : function(){
3505 var items = this.getItems();
3507 items.each(function(f){
3518 * @return {BasicForm} this
3521 var items = this.getItems();
3522 items.each(function(f){
3526 Roo.each(this.childForms || [], function (f) {
3533 getItems : function()
3535 var r=new Roo.util.MixedCollection(false, function(o){
3536 return o.id || (o.id = Roo.id());
3538 var iter = function(el) {
3545 Roo.each(el.items,function(e) {
3564 * Ext JS Library 1.1.1
3565 * Copyright(c) 2006-2007, Ext JS, LLC.
3567 * Originally Released Under LGPL - original licence link has changed is not relivant.
3570 * <script type="text/javascript">
3573 * @class Roo.form.VTypes
3574 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
3577 Roo.form.VTypes = function(){
3578 // closure these in so they are only created once.
3579 var alpha = /^[a-zA-Z_]+$/;
3580 var alphanum = /^[a-zA-Z0-9_]+$/;
3581 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
3582 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
3584 // All these messages and functions are configurable
3587 * The function used to validate email addresses
3588 * @param {String} value The email address
3590 'email' : function(v){
3591 return email.test(v);
3594 * The error text to display when the email validation function returns false
3597 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
3599 * The keystroke filter mask to be applied on email input
3602 'emailMask' : /[a-z0-9_\.\-@]/i,
3605 * The function used to validate URLs
3606 * @param {String} value The URL
3608 'url' : function(v){
3612 * The error text to display when the url validation function returns false
3615 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
3618 * The function used to validate alpha values
3619 * @param {String} value The value
3621 'alpha' : function(v){
3622 return alpha.test(v);
3625 * The error text to display when the alpha validation function returns false
3628 'alphaText' : 'This field should only contain letters and _',
3630 * The keystroke filter mask to be applied on alpha input
3633 'alphaMask' : /[a-z_]/i,
3636 * The function used to validate alphanumeric values
3637 * @param {String} value The value
3639 'alphanum' : function(v){
3640 return alphanum.test(v);
3643 * The error text to display when the alphanumeric validation function returns false
3646 'alphanumText' : 'This field should only contain letters, numbers and _',
3648 * The keystroke filter mask to be applied on alphanumeric input
3651 'alphanumMask' : /[a-z0-9_]/i
3661 * @class Roo.bootstrap.Input
3662 * @extends Roo.bootstrap.Component
3663 * Bootstrap Input class
3664 * @cfg {Boolean} disabled is it disabled
3665 * @cfg {String} fieldLabel - the label associated
3666 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3667 * @cfg {String} name name of the input
3668 * @cfg {string} fieldLabel - the label associated
3669 * @cfg {string} inputType - input / file submit ...
3670 * @cfg {string} placeholder - placeholder to put in text.
3671 * @cfg {string} before - input group add on before
3672 * @cfg {string} after - input group add on after
3673 * @cfg {string} size - (lg|sm) or leave empty..
3674 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3675 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3676 * @cfg {Number} md colspan out of 12 for computer-sized screens
3677 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3678 * @cfg {string} value default value of the input
3679 * @cfg {Number} labelWidth set the width of label (0-12)
3680 * @cfg {String} labelAlign (top|left)
3684 * Create a new Input
3685 * @param {Object} config The config object
3688 Roo.bootstrap.Input = function(config){
3689 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3694 * Fires when this field receives input focus.
3695 * @param {Roo.form.Field} this
3700 * Fires when this field loses input focus.
3701 * @param {Roo.form.Field} this
3706 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3707 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3708 * @param {Roo.form.Field} this
3709 * @param {Roo.EventObject} e The event object
3714 * Fires just before the field blurs if the field value has changed.
3715 * @param {Roo.form.Field} this
3716 * @param {Mixed} newValue The new value
3717 * @param {Mixed} oldValue The original value
3722 * Fires after the field has been marked as invalid.
3723 * @param {Roo.form.Field} this
3724 * @param {String} msg The validation message
3729 * Fires after the field has been validated with no errors.
3730 * @param {Roo.form.Field} this
3735 * Fires after the key up
3736 * @param {Roo.form.Field} this
3737 * @param {Roo.EventObject} e The event Object
3743 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3745 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3746 automatic validation (defaults to "keyup").
3748 validationEvent : "keyup",
3750 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3752 validateOnBlur : true,
3754 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3756 validationDelay : 250,
3758 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3760 focusClass : "x-form-focus", // not needed???
3764 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3766 invalidClass : "has-error",
3769 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3771 selectOnFocus : false,
3774 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3778 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3783 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3785 disableKeyFilter : false,
3788 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3792 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3796 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3798 blankText : "This field is required",
3801 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3805 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3807 maxLength : Number.MAX_VALUE,
3809 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3811 minLengthText : "The minimum length for this field is {0}",
3813 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3815 maxLengthText : "The maximum length for this field is {0}",
3819 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3820 * If available, this function will be called only after the basic validators all return true, and will be passed the
3821 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3825 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3826 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3827 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
3831 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3853 parentLabelAlign : function()
3856 while (parent.parent()) {
3857 parent = parent.parent();
3858 if (typeof(parent.labelAlign) !='undefined') {
3859 return parent.labelAlign;
3866 getAutoCreate : function(){
3868 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
3874 if(this.inputType != 'hidden'){
3875 cfg.cls = 'form-group' //input-group
3881 type : this.inputType,
3883 cls : 'form-control',
3884 placeholder : this.placeholder || ''
3888 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
3889 input.maxLength = this.maxLength;
3892 if (this.disabled) {
3893 input.disabled=true;
3897 input.name = this.name;
3900 input.cls += ' input-' + this.size;
3903 ['xs','sm','md','lg'].map(function(size){
3904 if (settings[size]) {
3905 cfg.cls += ' col-' + size + '-' + settings[size];
3909 var inputblock = input;
3911 if (this.before || this.after) {
3914 cls : 'input-group',
3918 inputblock.cn.push({
3920 cls : 'input-group-addon',
3924 inputblock.cn.push(input);
3926 inputblock.cn.push({
3928 cls : 'input-group-addon',
3935 if (align ==='left' && this.fieldLabel.length) {
3936 Roo.log("left and has label");
3942 cls : 'control-label col-sm-' + this.labelWidth,
3943 html : this.fieldLabel
3947 cls : "col-sm-" + (12 - this.labelWidth),
3954 } else if ( this.fieldLabel.length) {
3960 //cls : 'input-group-addon',
3961 html : this.fieldLabel
3971 Roo.log(" no label && no align");
3985 * return the real input element.
3987 inputEl: function ()
3989 return this.el.select('input.form-control',true).first();
3991 setDisabled : function(v)
3993 var i = this.inputEl().dom;
3995 i.removeAttribute('disabled');
3999 i.setAttribute('disabled','true');
4001 initEvents : function()
4004 this.inputEl().on("keydown" , this.fireKey, this);
4005 this.inputEl().on("focus", this.onFocus, this);
4006 this.inputEl().on("blur", this.onBlur, this);
4008 this.inputEl().relayEvent('keyup', this);
4010 // reference to original value for reset
4011 this.originalValue = this.getValue();
4012 //Roo.form.TextField.superclass.initEvents.call(this);
4013 if(this.validationEvent == 'keyup'){
4014 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
4015 this.inputEl().on('keyup', this.filterValidation, this);
4017 else if(this.validationEvent !== false){
4018 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
4021 if(this.selectOnFocus){
4022 this.on("focus", this.preFocus, this);
4025 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
4026 this.inputEl().on("keypress", this.filterKeys, this);
4029 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
4030 this.el.on("click", this.autoSize, this);
4033 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
4034 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
4038 filterValidation : function(e){
4039 if(!e.isNavKeyPress()){
4040 this.validationTask.delay(this.validationDelay);
4044 * Validates the field value
4045 * @return {Boolean} True if the value is valid, else false
4047 validate : function(){
4048 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
4049 if(this.disabled || this.validateValue(this.getRawValue())){
4050 this.clearInvalid();
4058 * Validates a value according to the field's validation rules and marks the field as invalid
4059 * if the validation fails
4060 * @param {Mixed} value The value to validate
4061 * @return {Boolean} True if the value is valid, else false
4063 validateValue : function(value){
4064 if(value.length < 1) { // if it's blank
4065 if(this.allowBlank){
4066 this.clearInvalid();
4069 this.markInvalid(this.blankText);
4073 if(value.length < this.minLength){
4074 this.markInvalid(String.format(this.minLengthText, this.minLength));
4077 if(value.length > this.maxLength){
4078 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
4082 var vt = Roo.form.VTypes;
4083 if(!vt[this.vtype](value, this)){
4084 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
4088 if(typeof this.validator == "function"){
4089 var msg = this.validator(value);
4091 this.markInvalid(msg);
4095 if(this.regex && !this.regex.test(value)){
4096 this.markInvalid(this.regexText);
4105 fireKey : function(e){
4106 //Roo.log('field ' + e.getKey());
4107 if(e.isNavKeyPress()){
4108 this.fireEvent("specialkey", this, e);
4111 focus : function (selectText){
4113 this.inputEl().focus();
4114 if(selectText === true){
4115 this.inputEl().dom.select();
4121 onFocus : function(){
4122 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4123 // this.el.addClass(this.focusClass);
4126 this.hasFocus = true;
4127 this.startValue = this.getValue();
4128 this.fireEvent("focus", this);
4132 beforeBlur : Roo.emptyFn,
4136 onBlur : function(){
4138 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4139 //this.el.removeClass(this.focusClass);
4141 this.hasFocus = false;
4142 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
4145 var v = this.getValue();
4146 if(String(v) !== String(this.startValue)){
4147 this.fireEvent('change', this, v, this.startValue);
4149 this.fireEvent("blur", this);
4153 * Resets the current field value to the originally loaded value and clears any validation messages
4156 this.setValue(this.originalValue);
4157 this.clearInvalid();
4160 * Returns the name of the field
4161 * @return {Mixed} name The name field
4163 getName: function(){
4167 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
4168 * @return {Mixed} value The field value
4170 getValue : function(){
4171 return this.inputEl().getValue();
4174 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
4175 * @return {Mixed} value The field value
4177 getRawValue : function(){
4178 var v = this.inputEl().getValue();
4184 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
4185 * @param {Mixed} value The value to set
4187 setRawValue : function(v){
4188 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4191 selectText : function(start, end){
4192 var v = this.getRawValue();
4194 start = start === undefined ? 0 : start;
4195 end = end === undefined ? v.length : end;
4196 var d = this.inputEl().dom;
4197 if(d.setSelectionRange){
4198 d.setSelectionRange(start, end);
4199 }else if(d.createTextRange){
4200 var range = d.createTextRange();
4201 range.moveStart("character", start);
4202 range.moveEnd("character", v.length-end);
4209 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
4210 * @param {Mixed} value The value to set
4212 setValue : function(v){
4215 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4221 processValue : function(value){
4222 if(this.stripCharsRe){
4223 var newValue = value.replace(this.stripCharsRe, '');
4224 if(newValue !== value){
4225 this.setRawValue(newValue);
4232 preFocus : function(){
4234 if(this.selectOnFocus){
4235 this.inputEl().dom.select();
4238 filterKeys : function(e){
4240 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
4243 var c = e.getCharCode(), cc = String.fromCharCode(c);
4244 if(Roo.isIE && (e.isSpecialKey() || !cc)){
4247 if(!this.maskRe.test(cc)){
4252 * Clear any invalid styles/messages for this field
4254 clearInvalid : function(){
4256 if(!this.el || this.preventMark){ // not rendered
4259 this.el.removeClass(this.invalidClass);
4261 switch(this.msgTarget){
4263 this.el.dom.qtip = '';
4266 this.el.dom.title = '';
4270 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
4275 this.errorIcon.dom.qtip = '';
4276 this.errorIcon.hide();
4277 this.un('resize', this.alignErrorIcon, this);
4281 var t = Roo.getDom(this.msgTarget);
4283 t.style.display = 'none';
4287 this.fireEvent('valid', this);
4290 * Mark this field as invalid
4291 * @param {String} msg The validation message
4293 markInvalid : function(msg){
4294 if(!this.el || this.preventMark){ // not rendered
4297 this.el.addClass(this.invalidClass);
4299 msg = msg || this.invalidText;
4300 switch(this.msgTarget){
4302 this.el.dom.qtip = msg;
4303 this.el.dom.qclass = 'x-form-invalid-tip';
4304 if(Roo.QuickTips){ // fix for floating editors interacting with DND
4305 Roo.QuickTips.enable();
4309 this.el.dom.title = msg;
4313 var elp = this.el.findParent('.x-form-element', 5, true);
4314 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
4315 this.errorEl.setWidth(elp.getWidth(true)-20);
4317 this.errorEl.update(msg);
4318 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
4321 if(!this.errorIcon){
4322 var elp = this.el.findParent('.x-form-element', 5, true);
4323 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
4325 this.alignErrorIcon();
4326 this.errorIcon.dom.qtip = msg;
4327 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
4328 this.errorIcon.show();
4329 this.on('resize', this.alignErrorIcon, this);
4332 var t = Roo.getDom(this.msgTarget);
4334 t.style.display = this.msgDisplay;
4338 this.fireEvent('invalid', this, msg);
4341 SafariOnKeyDown : function(event)
4343 // this is a workaround for a password hang bug on chrome/ webkit.
4345 var isSelectAll = false;
4347 if(this.inputEl().dom.selectionEnd > 0){
4348 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
4350 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
4351 event.preventDefault();
4356 if(isSelectAll){ // backspace and delete key
4358 event.preventDefault();
4359 // this is very hacky as keydown always get's upper case.
4361 var cc = String.fromCharCode(event.getCharCode());
4362 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
4378 * @class Roo.bootstrap.TextArea
4379 * @extends Roo.bootstrap.Input
4380 * Bootstrap TextArea class
4381 * @cfg {Number} cols Specifies the visible width of a text area
4382 * @cfg {Number} rows Specifies the visible number of lines in a text area
4383 * @cfg {Number} readOnly Specifies that a text area should be read-only
4384 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
4385 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
4386 * @cfg {string} html text
4389 * Create a new TextArea
4390 * @param {Object} config The config object
4393 Roo.bootstrap.TextArea = function(config){
4394 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
4398 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
4408 getAutoCreate : function(){
4410 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4421 value : this.value || '',
4422 html: this.html || '',
4423 cls : 'form-control',
4424 placeholder : this.placeholder || ''
4428 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4429 input.maxLength = this.maxLength;
4433 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
4437 input.cols = this.cols;
4440 if (this.readOnly) {
4441 input.readonly = true;
4445 input.name = this.name;
4449 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
4453 ['xs','sm','md','lg'].map(function(size){
4454 if (settings[size]) {
4455 cfg.cls += ' col-' + size + '-' + settings[size];
4459 var inputblock = input;
4461 if (this.before || this.after) {
4464 cls : 'input-group',
4468 inputblock.cn.push({
4470 cls : 'input-group-addon',
4474 inputblock.cn.push(input);
4476 inputblock.cn.push({
4478 cls : 'input-group-addon',
4485 if (align ==='left' && this.fieldLabel.length) {
4486 Roo.log("left and has label");
4492 cls : 'control-label col-sm-' + this.labelWidth,
4493 html : this.fieldLabel
4497 cls : "col-sm-" + (12 - this.labelWidth),
4504 } else if ( this.fieldLabel.length) {
4510 //cls : 'input-group-addon',
4511 html : this.fieldLabel
4521 Roo.log(" no label && no align");
4531 if (this.disabled) {
4532 input.disabled=true;
4539 * return the real textarea element.
4541 inputEl: function ()
4543 return this.el.select('textarea.form-control',true).first();
4551 * trigger field - base class for combo..
4556 * @class Roo.bootstrap.TriggerField
4557 * @extends Roo.bootstrap.Input
4558 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
4559 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
4560 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
4561 * for which you can provide a custom implementation. For example:
4563 var trigger = new Roo.bootstrap.TriggerField();
4564 trigger.onTriggerClick = myTriggerFn;
4565 trigger.applyTo('my-field');
4568 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
4569 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
4570 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
4571 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
4573 * Create a new TriggerField.
4574 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
4575 * to the base TextField)
4577 Roo.bootstrap.TriggerField = function(config){
4578 this.mimicing = false;
4579 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
4582 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
4584 * @cfg {String} triggerClass A CSS class to apply to the trigger
4587 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
4591 /** @cfg {Boolean} grow @hide */
4592 /** @cfg {Number} growMin @hide */
4593 /** @cfg {Number} growMax @hide */
4599 autoSize: Roo.emptyFn,
4606 actionMode : 'wrap',
4610 getAutoCreate : function(){
4612 var parent = this.parent();
4614 var align = this.parentLabelAlign();
4619 cls: 'form-group' //input-group
4626 type : this.inputType,
4627 cls : 'form-control',
4628 autocomplete: 'off',
4629 placeholder : this.placeholder || ''
4633 input.name = this.name;
4636 input.cls += ' input-' + this.size;
4639 cls: 'combobox-container input-group',
4644 cls: 'form-hidden-field'
4649 cls : 'typeahead typeahead-long dropdown-menu',
4650 style : 'display:none'
4654 cls : 'input-group-addon btn dropdown-toggle',
4662 cls: 'combobox-clear',
4679 if (align ==='left' && this.fieldLabel.length) {
4683 Roo.log("left and has label");
4689 cls : 'col-sm-2 control-label',
4690 html : this.fieldLabel
4701 } else if ( this.fieldLabel.length) {
4707 //cls : 'input-group-addon',
4708 html : this.fieldLabel
4718 Roo.log(" no label && no align");
4725 ['xs','sm','md','lg'].map(function(size){
4726 if (settings[size]) {
4727 cfg.cls += ' col-' + size + '-' + settings[size];
4733 if (this.disabled) {
4734 input.disabled=true;
4743 onResize : function(w, h){
4744 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
4745 // if(typeof w == 'number'){
4746 // var x = w - this.trigger.getWidth();
4747 // this.inputEl().setWidth(this.adjustWidth('input', x));
4748 // this.trigger.setStyle('left', x+'px');
4753 adjustSize : Roo.BoxComponent.prototype.adjustSize,
4756 getResizeEl : function(){
4757 return this.inputEl();
4761 getPositionEl : function(){
4762 return this.inputEl();
4766 alignErrorIcon : function(){
4767 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
4771 initEvents : function(){
4773 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
4774 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
4776 this.trigger = this.el.select('span.dropdown-toggle',true).first();
4777 if(this.hideTrigger){
4778 this.trigger.setDisplayed(false);
4780 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
4781 //this.trigger.addClassOnOver('x-form-trigger-over');
4782 //this.trigger.addClassOnClick('x-form-trigger-click');
4785 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
4790 initTrigger : function(){
4795 onDestroy : function(){
4797 this.trigger.removeAllListeners();
4798 // this.trigger.remove();
4801 // this.wrap.remove();
4803 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
4807 onFocus : function(){
4808 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
4811 this.wrap.addClass('x-trigger-wrap-focus');
4812 this.mimicing = true;
4813 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
4814 if(this.monitorTab){
4815 this.el.on("keydown", this.checkTab, this);
4822 checkTab : function(e){
4823 if(e.getKey() == e.TAB){
4829 onBlur : function(){
4834 mimicBlur : function(e, t){
4836 if(!this.wrap.contains(t) && this.validateBlur()){
4843 triggerBlur : function(){
4844 this.mimicing = false;
4845 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
4846 if(this.monitorTab){
4847 this.el.un("keydown", this.checkTab, this);
4849 //this.wrap.removeClass('x-trigger-wrap-focus');
4850 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
4854 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
4855 validateBlur : function(e, t){
4860 onDisable : function(){
4861 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
4863 // this.wrap.addClass('x-item-disabled');
4868 onEnable : function(){
4869 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
4871 // this.el.removeClass('x-item-disabled');
4876 onShow : function(){
4877 var ae = this.getActionEl();
4880 ae.dom.style.display = '';
4881 ae.dom.style.visibility = 'visible';
4887 onHide : function(){
4888 var ae = this.getActionEl();
4889 ae.dom.style.display = 'none';
4893 * The function that should handle the trigger's click event. This method does nothing by default until overridden
4894 * by an implementing function.
4896 * @param {EventObject} e
4898 onTriggerClick : Roo.emptyFn
4902 * Ext JS Library 1.1.1
4903 * Copyright(c) 2006-2007, Ext JS, LLC.
4905 * Originally Released Under LGPL - original licence link has changed is not relivant.
4908 * <script type="text/javascript">
4913 * @class Roo.data.SortTypes
4915 * Defines the default sorting (casting?) comparison functions used when sorting data.
4917 Roo.data.SortTypes = {
4919 * Default sort that does nothing
4920 * @param {Mixed} s The value being converted
4921 * @return {Mixed} The comparison value
4928 * The regular expression used to strip tags
4932 stripTagsRE : /<\/?[^>]+>/gi,
4935 * Strips all HTML tags to sort on text only
4936 * @param {Mixed} s The value being converted
4937 * @return {String} The comparison value
4939 asText : function(s){
4940 return String(s).replace(this.stripTagsRE, "");
4944 * Strips all HTML tags to sort on text only - Case insensitive
4945 * @param {Mixed} s The value being converted
4946 * @return {String} The comparison value
4948 asUCText : function(s){
4949 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4953 * Case insensitive string
4954 * @param {Mixed} s The value being converted
4955 * @return {String} The comparison value
4957 asUCString : function(s) {
4958 return String(s).toUpperCase();
4963 * @param {Mixed} s The value being converted
4964 * @return {Number} The comparison value
4966 asDate : function(s) {
4970 if(s instanceof Date){
4973 return Date.parse(String(s));
4978 * @param {Mixed} s The value being converted
4979 * @return {Float} The comparison value
4981 asFloat : function(s) {
4982 var val = parseFloat(String(s).replace(/,/g, ""));
4983 if(isNaN(val)) val = 0;
4989 * @param {Mixed} s The value being converted
4990 * @return {Number} The comparison value
4992 asInt : function(s) {
4993 var val = parseInt(String(s).replace(/,/g, ""));
4994 if(isNaN(val)) val = 0;
4999 * Ext JS Library 1.1.1
5000 * Copyright(c) 2006-2007, Ext JS, LLC.
5002 * Originally Released Under LGPL - original licence link has changed is not relivant.
5005 * <script type="text/javascript">
5009 * @class Roo.data.Record
5010 * Instances of this class encapsulate both record <em>definition</em> information, and record
5011 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
5012 * to access Records cached in an {@link Roo.data.Store} object.<br>
5014 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
5015 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
5018 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
5020 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
5021 * {@link #create}. The parameters are the same.
5022 * @param {Array} data An associative Array of data values keyed by the field name.
5023 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
5024 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
5025 * not specified an integer id is generated.
5027 Roo.data.Record = function(data, id){
5028 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
5033 * Generate a constructor for a specific record layout.
5034 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
5035 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
5036 * Each field definition object may contain the following properties: <ul>
5037 * <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,
5038 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
5039 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
5040 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
5041 * is being used, then this is a string containing the javascript expression to reference the data relative to
5042 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
5043 * to the data item relative to the record element. If the mapping expression is the same as the field name,
5044 * this may be omitted.</p></li>
5045 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
5046 * <ul><li>auto (Default, implies no conversion)</li>
5051 * <li>date</li></ul></p></li>
5052 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
5053 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
5054 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
5055 * by the Reader into an object that will be stored in the Record. It is passed the
5056 * following parameters:<ul>
5057 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
5059 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
5061 * <br>usage:<br><pre><code>
5062 var TopicRecord = Roo.data.Record.create(
5063 {name: 'title', mapping: 'topic_title'},
5064 {name: 'author', mapping: 'username'},
5065 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
5066 {name: 'lastPost', mapping: 'post_time', type: 'date'},
5067 {name: 'lastPoster', mapping: 'user2'},
5068 {name: 'excerpt', mapping: 'post_text'}
5071 var myNewRecord = new TopicRecord({
5072 title: 'Do my job please',
5075 lastPost: new Date(),
5076 lastPoster: 'Animal',
5077 excerpt: 'No way dude!'
5079 myStore.add(myNewRecord);
5084 Roo.data.Record.create = function(o){
5086 f.superclass.constructor.apply(this, arguments);
5088 Roo.extend(f, Roo.data.Record);
5089 var p = f.prototype;
5090 p.fields = new Roo.util.MixedCollection(false, function(field){
5093 for(var i = 0, len = o.length; i < len; i++){
5094 p.fields.add(new Roo.data.Field(o[i]));
5096 f.getField = function(name){
5097 return p.fields.get(name);
5102 Roo.data.Record.AUTO_ID = 1000;
5103 Roo.data.Record.EDIT = 'edit';
5104 Roo.data.Record.REJECT = 'reject';
5105 Roo.data.Record.COMMIT = 'commit';
5107 Roo.data.Record.prototype = {
5109 * Readonly flag - true if this record has been modified.
5118 join : function(store){
5123 * Set the named field to the specified value.
5124 * @param {String} name The name of the field to set.
5125 * @param {Object} value The value to set the field to.
5127 set : function(name, value){
5128 if(this.data[name] == value){
5135 if(typeof this.modified[name] == 'undefined'){
5136 this.modified[name] = this.data[name];
5138 this.data[name] = value;
5139 if(!this.editing && this.store){
5140 this.store.afterEdit(this);
5145 * Get the value of the named field.
5146 * @param {String} name The name of the field to get the value of.
5147 * @return {Object} The value of the field.
5149 get : function(name){
5150 return this.data[name];
5154 beginEdit : function(){
5155 this.editing = true;
5160 cancelEdit : function(){
5161 this.editing = false;
5162 delete this.modified;
5166 endEdit : function(){
5167 this.editing = false;
5168 if(this.dirty && this.store){
5169 this.store.afterEdit(this);
5174 * Usually called by the {@link Roo.data.Store} which owns the Record.
5175 * Rejects all changes made to the Record since either creation, or the last commit operation.
5176 * Modified fields are reverted to their original values.
5178 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5179 * of reject operations.
5181 reject : function(){
5182 var m = this.modified;
5184 if(typeof m[n] != "function"){
5185 this.data[n] = m[n];
5189 delete this.modified;
5190 this.editing = false;
5192 this.store.afterReject(this);
5197 * Usually called by the {@link Roo.data.Store} which owns the Record.
5198 * Commits all changes made to the Record since either creation, or the last commit operation.
5200 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5201 * of commit operations.
5203 commit : function(){
5205 delete this.modified;
5206 this.editing = false;
5208 this.store.afterCommit(this);
5213 hasError : function(){
5214 return this.error != null;
5218 clearError : function(){
5223 * Creates a copy of this record.
5224 * @param {String} id (optional) A new record id if you don't want to use this record's id
5227 copy : function(newId) {
5228 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
5232 * Ext JS Library 1.1.1
5233 * Copyright(c) 2006-2007, Ext JS, LLC.
5235 * Originally Released Under LGPL - original licence link has changed is not relivant.
5238 * <script type="text/javascript">
5244 * @class Roo.data.Store
5245 * @extends Roo.util.Observable
5246 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
5247 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
5249 * 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
5250 * has no knowledge of the format of the data returned by the Proxy.<br>
5252 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
5253 * instances from the data object. These records are cached and made available through accessor functions.
5255 * Creates a new Store.
5256 * @param {Object} config A config object containing the objects needed for the Store to access data,
5257 * and read the data into Records.
5259 Roo.data.Store = function(config){
5260 this.data = new Roo.util.MixedCollection(false);
5261 this.data.getKey = function(o){
5264 this.baseParams = {};
5271 "multisort" : "_multisort"
5274 if(config && config.data){
5275 this.inlineData = config.data;
5279 Roo.apply(this, config);
5281 if(this.reader){ // reader passed
5282 this.reader = Roo.factory(this.reader, Roo.data);
5283 this.reader.xmodule = this.xmodule || false;
5284 if(!this.recordType){
5285 this.recordType = this.reader.recordType;
5287 if(this.reader.onMetaChange){
5288 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
5292 if(this.recordType){
5293 this.fields = this.recordType.prototype.fields;
5299 * @event datachanged
5300 * Fires when the data cache has changed, and a widget which is using this Store
5301 * as a Record cache should refresh its view.
5302 * @param {Store} this
5307 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
5308 * @param {Store} this
5309 * @param {Object} meta The JSON metadata
5314 * Fires when Records have been added to the Store
5315 * @param {Store} this
5316 * @param {Roo.data.Record[]} records The array of Records added
5317 * @param {Number} index The index at which the record(s) were added
5322 * Fires when a Record has been removed from the Store
5323 * @param {Store} this
5324 * @param {Roo.data.Record} record The Record that was removed
5325 * @param {Number} index The index at which the record was removed
5330 * Fires when a Record has been updated
5331 * @param {Store} this
5332 * @param {Roo.data.Record} record The Record that was updated
5333 * @param {String} operation The update operation being performed. Value may be one of:
5335 Roo.data.Record.EDIT
5336 Roo.data.Record.REJECT
5337 Roo.data.Record.COMMIT
5343 * Fires when the data cache has been cleared.
5344 * @param {Store} this
5349 * Fires before a request is made for a new data object. If the beforeload handler returns false
5350 * the load action will be canceled.
5351 * @param {Store} this
5352 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5356 * @event beforeloadadd
5357 * Fires after a new set of Records has been loaded.
5358 * @param {Store} this
5359 * @param {Roo.data.Record[]} records The Records that were loaded
5360 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5362 beforeloadadd : true,
5365 * Fires after a new set of Records has been loaded, before they are added to the store.
5366 * @param {Store} this
5367 * @param {Roo.data.Record[]} records The Records that were loaded
5368 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5369 * @params {Object} return from reader
5373 * @event loadexception
5374 * Fires if an exception occurs in the Proxy during loading.
5375 * Called with the signature of the Proxy's "loadexception" event.
5376 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
5379 * @param {Object} return from JsonData.reader() - success, totalRecords, records
5380 * @param {Object} load options
5381 * @param {Object} jsonData from your request (normally this contains the Exception)
5383 loadexception : true
5387 this.proxy = Roo.factory(this.proxy, Roo.data);
5388 this.proxy.xmodule = this.xmodule || false;
5389 this.relayEvents(this.proxy, ["loadexception"]);
5391 this.sortToggle = {};
5392 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
5394 Roo.data.Store.superclass.constructor.call(this);
5396 if(this.inlineData){
5397 this.loadData(this.inlineData);
5398 delete this.inlineData;
5402 Roo.extend(Roo.data.Store, Roo.util.Observable, {
5404 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
5405 * without a remote query - used by combo/forms at present.
5409 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
5412 * @cfg {Array} data Inline data to be loaded when the store is initialized.
5415 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
5416 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
5419 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
5420 * on any HTTP request
5423 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
5426 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
5430 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
5431 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
5436 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
5437 * loaded or when a record is removed. (defaults to false).
5439 pruneModifiedRecords : false,
5445 * Add Records to the Store and fires the add event.
5446 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
5448 add : function(records){
5449 records = [].concat(records);
5450 for(var i = 0, len = records.length; i < len; i++){
5451 records[i].join(this);
5453 var index = this.data.length;
5454 this.data.addAll(records);
5455 this.fireEvent("add", this, records, index);
5459 * Remove a Record from the Store and fires the remove event.
5460 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
5462 remove : function(record){
5463 var index = this.data.indexOf(record);
5464 this.data.removeAt(index);
5465 if(this.pruneModifiedRecords){
5466 this.modified.remove(record);
5468 this.fireEvent("remove", this, record, index);
5472 * Remove all Records from the Store and fires the clear event.
5474 removeAll : function(){
5476 if(this.pruneModifiedRecords){
5479 this.fireEvent("clear", this);
5483 * Inserts Records to the Store at the given index and fires the add event.
5484 * @param {Number} index The start index at which to insert the passed Records.
5485 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
5487 insert : function(index, records){
5488 records = [].concat(records);
5489 for(var i = 0, len = records.length; i < len; i++){
5490 this.data.insert(index, records[i]);
5491 records[i].join(this);
5493 this.fireEvent("add", this, records, index);
5497 * Get the index within the cache of the passed Record.
5498 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
5499 * @return {Number} The index of the passed Record. Returns -1 if not found.
5501 indexOf : function(record){
5502 return this.data.indexOf(record);
5506 * Get the index within the cache of the Record with the passed id.
5507 * @param {String} id The id of the Record to find.
5508 * @return {Number} The index of the Record. Returns -1 if not found.
5510 indexOfId : function(id){
5511 return this.data.indexOfKey(id);
5515 * Get the Record with the specified id.
5516 * @param {String} id The id of the Record to find.
5517 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
5519 getById : function(id){
5520 return this.data.key(id);
5524 * Get the Record at the specified index.
5525 * @param {Number} index The index of the Record to find.
5526 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
5528 getAt : function(index){
5529 return this.data.itemAt(index);
5533 * Returns a range of Records between specified indices.
5534 * @param {Number} startIndex (optional) The starting index (defaults to 0)
5535 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
5536 * @return {Roo.data.Record[]} An array of Records
5538 getRange : function(start, end){
5539 return this.data.getRange(start, end);
5543 storeOptions : function(o){
5544 o = Roo.apply({}, o);
5547 this.lastOptions = o;
5551 * Loads the Record cache from the configured Proxy using the configured Reader.
5553 * If using remote paging, then the first load call must specify the <em>start</em>
5554 * and <em>limit</em> properties in the options.params property to establish the initial
5555 * position within the dataset, and the number of Records to cache on each read from the Proxy.
5557 * <strong>It is important to note that for remote data sources, loading is asynchronous,
5558 * and this call will return before the new data has been loaded. Perform any post-processing
5559 * in a callback function, or in a "load" event handler.</strong>
5561 * @param {Object} options An object containing properties which control loading options:<ul>
5562 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
5563 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
5564 * passed the following arguments:<ul>
5565 * <li>r : Roo.data.Record[]</li>
5566 * <li>options: Options object from the load call</li>
5567 * <li>success: Boolean success indicator</li></ul></li>
5568 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
5569 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
5572 load : function(options){
5573 options = options || {};
5574 if(this.fireEvent("beforeload", this, options) !== false){
5575 this.storeOptions(options);
5576 var p = Roo.apply(options.params || {}, this.baseParams);
5577 // if meta was not loaded from remote source.. try requesting it.
5578 if (!this.reader.metaFromRemote) {
5581 if(this.sortInfo && this.remoteSort){
5582 var pn = this.paramNames;
5583 p[pn["sort"]] = this.sortInfo.field;
5584 p[pn["dir"]] = this.sortInfo.direction;
5586 if (this.multiSort) {
5587 var pn = this.paramNames;
5588 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
5591 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5596 * Reloads the Record cache from the configured Proxy using the configured Reader and
5597 * the options from the last load operation performed.
5598 * @param {Object} options (optional) An object containing properties which may override the options
5599 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5600 * the most recently used options are reused).
5602 reload : function(options){
5603 this.load(Roo.applyIf(options||{}, this.lastOptions));
5607 // Called as a callback by the Reader during a load operation.
5608 loadRecords : function(o, options, success){
5609 if(!o || success === false){
5610 if(success !== false){
5611 this.fireEvent("load", this, [], options, o);
5613 if(options.callback){
5614 options.callback.call(options.scope || this, [], options, false);
5618 // if data returned failure - throw an exception.
5619 if (o.success === false) {
5620 // show a message if no listener is registered.
5621 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
5622 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
5624 // loadmask wil be hooked into this..
5625 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
5628 var r = o.records, t = o.totalRecords || r.length;
5630 this.fireEvent("beforeloadadd", this, r, options, o);
5632 if(!options || options.add !== true){
5633 if(this.pruneModifiedRecords){
5636 for(var i = 0, len = r.length; i < len; i++){
5640 this.data = this.snapshot;
5641 delete this.snapshot;
5644 this.data.addAll(r);
5645 this.totalLength = t;
5647 this.fireEvent("datachanged", this);
5649 this.totalLength = Math.max(t, this.data.length+r.length);
5652 this.fireEvent("load", this, r, options, o);
5653 if(options.callback){
5654 options.callback.call(options.scope || this, r, options, true);
5660 * Loads data from a passed data block. A Reader which understands the format of the data
5661 * must have been configured in the constructor.
5662 * @param {Object} data The data block from which to read the Records. The format of the data expected
5663 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5664 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5666 loadData : function(o, append){
5667 var r = this.reader.readRecords(o);
5668 this.loadRecords(r, {add: append}, true);
5672 * Gets the number of cached records.
5674 * <em>If using paging, this may not be the total size of the dataset. If the data object
5675 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5676 * the data set size</em>
5678 getCount : function(){
5679 return this.data.length || 0;
5683 * Gets the total number of records in the dataset as returned by the server.
5685 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5686 * the dataset size</em>
5688 getTotalCount : function(){
5689 return this.totalLength || 0;
5693 * Returns the sort state of the Store as an object with two properties:
5695 field {String} The name of the field by which the Records are sorted
5696 direction {String} The sort order, "ASC" or "DESC"
5699 getSortState : function(){
5700 return this.sortInfo;
5704 applySort : function(){
5705 if(this.sortInfo && !this.remoteSort){
5706 var s = this.sortInfo, f = s.field;
5707 var st = this.fields.get(f).sortType;
5708 var fn = function(r1, r2){
5709 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5710 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5712 this.data.sort(s.direction, fn);
5713 if(this.snapshot && this.snapshot != this.data){
5714 this.snapshot.sort(s.direction, fn);
5720 * Sets the default sort column and order to be used by the next load operation.
5721 * @param {String} fieldName The name of the field to sort by.
5722 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5724 setDefaultSort : function(field, dir){
5725 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5730 * If remote sorting is used, the sort is performed on the server, and the cache is
5731 * reloaded. If local sorting is used, the cache is sorted internally.
5732 * @param {String} fieldName The name of the field to sort by.
5733 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5735 sort : function(fieldName, dir){
5736 var f = this.fields.get(fieldName);
5738 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
5740 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
5741 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5746 this.sortToggle[f.name] = dir;
5747 this.sortInfo = {field: f.name, direction: dir};
5748 if(!this.remoteSort){
5750 this.fireEvent("datachanged", this);
5752 this.load(this.lastOptions);
5757 * Calls the specified function for each of the Records in the cache.
5758 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5759 * Returning <em>false</em> aborts and exits the iteration.
5760 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5762 each : function(fn, scope){
5763 this.data.each(fn, scope);
5767 * Gets all records modified since the last commit. Modified records are persisted across load operations
5768 * (e.g., during paging).
5769 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5771 getModifiedRecords : function(){
5772 return this.modified;
5776 createFilterFn : function(property, value, anyMatch){
5777 if(!value.exec){ // not a regex
5778 value = String(value);
5779 if(value.length == 0){
5782 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5785 return value.test(r.data[property]);
5790 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5791 * @param {String} property A field on your records
5792 * @param {Number} start The record index to start at (defaults to 0)
5793 * @param {Number} end The last record index to include (defaults to length - 1)
5794 * @return {Number} The sum
5796 sum : function(property, start, end){
5797 var rs = this.data.items, v = 0;
5799 end = (end || end === 0) ? end : rs.length-1;
5801 for(var i = start; i <= end; i++){
5802 v += (rs[i].data[property] || 0);
5808 * Filter the records by a specified property.
5809 * @param {String} field A field on your records
5810 * @param {String/RegExp} value Either a string that the field
5811 * should start with or a RegExp to test against the field
5812 * @param {Boolean} anyMatch True to match any part not just the beginning
5814 filter : function(property, value, anyMatch){
5815 var fn = this.createFilterFn(property, value, anyMatch);
5816 return fn ? this.filterBy(fn) : this.clearFilter();
5820 * Filter by a function. The specified function will be called with each
5821 * record in this data source. If the function returns true the record is included,
5822 * otherwise it is filtered.
5823 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5824 * @param {Object} scope (optional) The scope of the function (defaults to this)
5826 filterBy : function(fn, scope){
5827 this.snapshot = this.snapshot || this.data;
5828 this.data = this.queryBy(fn, scope||this);
5829 this.fireEvent("datachanged", this);
5833 * Query the records by a specified property.
5834 * @param {String} field A field on your records
5835 * @param {String/RegExp} value Either a string that the field
5836 * should start with or a RegExp to test against the field
5837 * @param {Boolean} anyMatch True to match any part not just the beginning
5838 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5840 query : function(property, value, anyMatch){
5841 var fn = this.createFilterFn(property, value, anyMatch);
5842 return fn ? this.queryBy(fn) : this.data.clone();
5846 * Query by a function. The specified function will be called with each
5847 * record in this data source. If the function returns true the record is included
5849 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5850 * @param {Object} scope (optional) The scope of the function (defaults to this)
5851 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5853 queryBy : function(fn, scope){
5854 var data = this.snapshot || this.data;
5855 return data.filterBy(fn, scope||this);
5859 * Collects unique values for a particular dataIndex from this store.
5860 * @param {String} dataIndex The property to collect
5861 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5862 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5863 * @return {Array} An array of the unique values
5865 collect : function(dataIndex, allowNull, bypassFilter){
5866 var d = (bypassFilter === true && this.snapshot) ?
5867 this.snapshot.items : this.data.items;
5868 var v, sv, r = [], l = {};
5869 for(var i = 0, len = d.length; i < len; i++){
5870 v = d[i].data[dataIndex];
5872 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5881 * Revert to a view of the Record cache with no filtering applied.
5882 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5884 clearFilter : function(suppressEvent){
5885 if(this.snapshot && this.snapshot != this.data){
5886 this.data = this.snapshot;
5887 delete this.snapshot;
5888 if(suppressEvent !== true){
5889 this.fireEvent("datachanged", this);
5895 afterEdit : function(record){
5896 if(this.modified.indexOf(record) == -1){
5897 this.modified.push(record);
5899 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5903 afterReject : function(record){
5904 this.modified.remove(record);
5905 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5909 afterCommit : function(record){
5910 this.modified.remove(record);
5911 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5915 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5916 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5918 commitChanges : function(){
5919 var m = this.modified.slice(0);
5921 for(var i = 0, len = m.length; i < len; i++){
5927 * Cancel outstanding changes on all changed records.
5929 rejectChanges : function(){
5930 var m = this.modified.slice(0);
5932 for(var i = 0, len = m.length; i < len; i++){
5937 onMetaChange : function(meta, rtype, o){
5938 this.recordType = rtype;
5939 this.fields = rtype.prototype.fields;
5940 delete this.snapshot;
5941 this.sortInfo = meta.sortInfo || this.sortInfo;
5943 this.fireEvent('metachange', this, this.reader.meta);
5947 * Ext JS Library 1.1.1
5948 * Copyright(c) 2006-2007, Ext JS, LLC.
5950 * Originally Released Under LGPL - original licence link has changed is not relivant.
5953 * <script type="text/javascript">
5957 * @class Roo.data.SimpleStore
5958 * @extends Roo.data.Store
5959 * Small helper class to make creating Stores from Array data easier.
5960 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5961 * @cfg {Array} fields An array of field definition objects, or field name strings.
5962 * @cfg {Array} data The multi-dimensional array of data
5964 * @param {Object} config
5966 Roo.data.SimpleStore = function(config){
5967 Roo.data.SimpleStore.superclass.constructor.call(this, {
5969 reader: new Roo.data.ArrayReader({
5972 Roo.data.Record.create(config.fields)
5974 proxy : new Roo.data.MemoryProxy(config.data)
5978 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5980 * Ext JS Library 1.1.1
5981 * Copyright(c) 2006-2007, Ext JS, LLC.
5983 * Originally Released Under LGPL - original licence link has changed is not relivant.
5986 * <script type="text/javascript">
5991 * @extends Roo.data.Store
5992 * @class Roo.data.JsonStore
5993 * Small helper class to make creating Stores for JSON data easier. <br/>
5995 var store = new Roo.data.JsonStore({
5996 url: 'get-images.php',
5998 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
6001 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
6002 * JsonReader and HttpProxy (unless inline data is provided).</b>
6003 * @cfg {Array} fields An array of field definition objects, or field name strings.
6005 * @param {Object} config
6007 Roo.data.JsonStore = function(c){
6008 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
6009 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
6010 reader: new Roo.data.JsonReader(c, c.fields)
6013 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
6015 * Ext JS Library 1.1.1
6016 * Copyright(c) 2006-2007, Ext JS, LLC.
6018 * Originally Released Under LGPL - original licence link has changed is not relivant.
6021 * <script type="text/javascript">
6025 Roo.data.Field = function(config){
6026 if(typeof config == "string"){
6027 config = {name: config};
6029 Roo.apply(this, config);
6035 var st = Roo.data.SortTypes;
6036 // named sortTypes are supported, here we look them up
6037 if(typeof this.sortType == "string"){
6038 this.sortType = st[this.sortType];
6041 // set default sortType for strings and dates
6045 this.sortType = st.asUCString;
6048 this.sortType = st.asDate;
6051 this.sortType = st.none;
6056 var stripRe = /[\$,%]/g;
6058 // prebuilt conversion function for this field, instead of
6059 // switching every time we're reading a value
6061 var cv, dateFormat = this.dateFormat;
6066 cv = function(v){ return v; };
6069 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
6073 return v !== undefined && v !== null && v !== '' ?
6074 parseInt(String(v).replace(stripRe, ""), 10) : '';
6079 return v !== undefined && v !== null && v !== '' ?
6080 parseFloat(String(v).replace(stripRe, ""), 10) : '';
6085 cv = function(v){ return v === true || v === "true" || v == 1; };
6092 if(v instanceof Date){
6096 if(dateFormat == "timestamp"){
6097 return new Date(v*1000);
6099 return Date.parseDate(v, dateFormat);
6101 var parsed = Date.parse(v);
6102 return parsed ? new Date(parsed) : null;
6111 Roo.data.Field.prototype = {
6119 * Ext JS Library 1.1.1
6120 * Copyright(c) 2006-2007, Ext JS, LLC.
6122 * Originally Released Under LGPL - original licence link has changed is not relivant.
6125 * <script type="text/javascript">
6128 // Base class for reading structured data from a data source. This class is intended to be
6129 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
6132 * @class Roo.data.DataReader
6133 * Base class for reading structured data from a data source. This class is intended to be
6134 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
6137 Roo.data.DataReader = function(meta, recordType){
6141 this.recordType = recordType instanceof Array ?
6142 Roo.data.Record.create(recordType) : recordType;
6145 Roo.data.DataReader.prototype = {
6147 * Create an empty record
6148 * @param {Object} data (optional) - overlay some values
6149 * @return {Roo.data.Record} record created.
6151 newRow : function(d) {
6153 this.recordType.prototype.fields.each(function(c) {
6155 case 'int' : da[c.name] = 0; break;
6156 case 'date' : da[c.name] = new Date(); break;
6157 case 'float' : da[c.name] = 0.0; break;
6158 case 'boolean' : da[c.name] = false; break;
6159 default : da[c.name] = ""; break;
6163 return new this.recordType(Roo.apply(da, d));
6168 * Ext JS Library 1.1.1
6169 * Copyright(c) 2006-2007, Ext JS, LLC.
6171 * Originally Released Under LGPL - original licence link has changed is not relivant.
6174 * <script type="text/javascript">
6178 * @class Roo.data.DataProxy
6179 * @extends Roo.data.Observable
6180 * This class is an abstract base class for implementations which provide retrieval of
6181 * unformatted data objects.<br>
6183 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
6184 * (of the appropriate type which knows how to parse the data object) to provide a block of
6185 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
6187 * Custom implementations must implement the load method as described in
6188 * {@link Roo.data.HttpProxy#load}.
6190 Roo.data.DataProxy = function(){
6194 * Fires before a network request is made to retrieve a data object.
6195 * @param {Object} This DataProxy object.
6196 * @param {Object} params The params parameter to the load function.
6201 * Fires before the load method's callback is called.
6202 * @param {Object} This DataProxy object.
6203 * @param {Object} o The data object.
6204 * @param {Object} arg The callback argument object passed to the load function.
6208 * @event loadexception
6209 * Fires if an Exception occurs during data retrieval.
6210 * @param {Object} This DataProxy object.
6211 * @param {Object} o The data object.
6212 * @param {Object} arg The callback argument object passed to the load function.
6213 * @param {Object} e The Exception.
6215 loadexception : true
6217 Roo.data.DataProxy.superclass.constructor.call(this);
6220 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
6223 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
6227 * Ext JS Library 1.1.1
6228 * Copyright(c) 2006-2007, Ext JS, LLC.
6230 * Originally Released Under LGPL - original licence link has changed is not relivant.
6233 * <script type="text/javascript">
6236 * @class Roo.data.MemoryProxy
6237 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
6238 * to the Reader when its load method is called.
6240 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
6242 Roo.data.MemoryProxy = function(data){
6246 Roo.data.MemoryProxy.superclass.constructor.call(this);
6250 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
6252 * Load data from the requested source (in this case an in-memory
6253 * data object passed to the constructor), read the data object into
6254 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6255 * process that block using the passed callback.
6256 * @param {Object} params This parameter is not used by the MemoryProxy class.
6257 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6258 * object into a block of Roo.data.Records.
6259 * @param {Function} callback The function into which to pass the block of Roo.data.records.
6260 * The function must be passed <ul>
6261 * <li>The Record block object</li>
6262 * <li>The "arg" argument from the load function</li>
6263 * <li>A boolean success indicator</li>
6265 * @param {Object} scope The scope in which to call the callback
6266 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6268 load : function(params, reader, callback, scope, arg){
6269 params = params || {};
6272 result = reader.readRecords(this.data);
6274 this.fireEvent("loadexception", this, arg, null, e);
6275 callback.call(scope, null, arg, false);
6278 callback.call(scope, result, arg, true);
6282 update : function(params, records){
6287 * Ext JS Library 1.1.1
6288 * Copyright(c) 2006-2007, Ext JS, LLC.
6290 * Originally Released Under LGPL - original licence link has changed is not relivant.
6293 * <script type="text/javascript">
6296 * @class Roo.data.HttpProxy
6297 * @extends Roo.data.DataProxy
6298 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
6299 * configured to reference a certain URL.<br><br>
6301 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
6302 * from which the running page was served.<br><br>
6304 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
6306 * Be aware that to enable the browser to parse an XML document, the server must set
6307 * the Content-Type header in the HTTP response to "text/xml".
6309 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
6310 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
6311 * will be used to make the request.
6313 Roo.data.HttpProxy = function(conn){
6314 Roo.data.HttpProxy.superclass.constructor.call(this);
6315 // is conn a conn config or a real conn?
6317 this.useAjax = !conn || !conn.events;
6321 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
6322 // thse are take from connection...
6325 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
6328 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
6329 * extra parameters to each request made by this object. (defaults to undefined)
6332 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
6333 * to each request made by this object. (defaults to undefined)
6336 * @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)
6339 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
6342 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
6348 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
6352 * Return the {@link Roo.data.Connection} object being used by this Proxy.
6353 * @return {Connection} The Connection object. This object may be used to subscribe to events on
6354 * a finer-grained basis than the DataProxy events.
6356 getConnection : function(){
6357 return this.useAjax ? Roo.Ajax : this.conn;
6361 * Load data from the configured {@link Roo.data.Connection}, read the data object into
6362 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
6363 * process that block using the passed callback.
6364 * @param {Object} params An object containing properties which are to be used as HTTP parameters
6365 * for the request to the remote server.
6366 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6367 * object into a block of Roo.data.Records.
6368 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6369 * The function must be passed <ul>
6370 * <li>The Record block object</li>
6371 * <li>The "arg" argument from the load function</li>
6372 * <li>A boolean success indicator</li>
6374 * @param {Object} scope The scope in which to call the callback
6375 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6377 load : function(params, reader, callback, scope, arg){
6378 if(this.fireEvent("beforeload", this, params) !== false){
6380 params : params || {},
6382 callback : callback,
6387 callback : this.loadResponse,
6391 Roo.applyIf(o, this.conn);
6392 if(this.activeRequest){
6393 Roo.Ajax.abort(this.activeRequest);
6395 this.activeRequest = Roo.Ajax.request(o);
6397 this.conn.request(o);
6400 callback.call(scope||this, null, arg, false);
6405 loadResponse : function(o, success, response){
6406 delete this.activeRequest;
6408 this.fireEvent("loadexception", this, o, response);
6409 o.request.callback.call(o.request.scope, null, o.request.arg, false);
6414 result = o.reader.read(response);
6416 this.fireEvent("loadexception", this, o, response, e);
6417 o.request.callback.call(o.request.scope, null, o.request.arg, false);
6421 this.fireEvent("load", this, o, o.request.arg);
6422 o.request.callback.call(o.request.scope, result, o.request.arg, true);
6426 update : function(dataSet){
6431 updateResponse : function(dataSet){
6436 * Ext JS Library 1.1.1
6437 * Copyright(c) 2006-2007, Ext JS, LLC.
6439 * Originally Released Under LGPL - original licence link has changed is not relivant.
6442 * <script type="text/javascript">
6446 * @class Roo.data.ScriptTagProxy
6447 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
6448 * other than the originating domain of the running page.<br><br>
6450 * <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
6451 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
6453 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
6454 * source code that is used as the source inside a <script> tag.<br><br>
6456 * In order for the browser to process the returned data, the server must wrap the data object
6457 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
6458 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
6459 * depending on whether the callback name was passed:
6462 boolean scriptTag = false;
6463 String cb = request.getParameter("callback");
6466 response.setContentType("text/javascript");
6468 response.setContentType("application/x-json");
6470 Writer out = response.getWriter();
6472 out.write(cb + "(");
6474 out.print(dataBlock.toJsonString());
6481 * @param {Object} config A configuration object.
6483 Roo.data.ScriptTagProxy = function(config){
6484 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
6485 Roo.apply(this, config);
6486 this.head = document.getElementsByTagName("head")[0];
6489 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
6491 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
6493 * @cfg {String} url The URL from which to request the data object.
6496 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
6500 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
6501 * the server the name of the callback function set up by the load call to process the returned data object.
6502 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
6503 * javascript output which calls this named function passing the data object as its only parameter.
6505 callbackParam : "callback",
6507 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
6508 * name to the request.
6513 * Load data from the configured URL, read the data object into
6514 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6515 * process that block using the passed callback.
6516 * @param {Object} params An object containing properties which are to be used as HTTP parameters
6517 * for the request to the remote server.
6518 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6519 * object into a block of Roo.data.Records.
6520 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6521 * The function must be passed <ul>
6522 * <li>The Record block object</li>
6523 * <li>The "arg" argument from the load function</li>
6524 * <li>A boolean success indicator</li>
6526 * @param {Object} scope The scope in which to call the callback
6527 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6529 load : function(params, reader, callback, scope, arg){
6530 if(this.fireEvent("beforeload", this, params) !== false){
6532 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
6535 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
6537 url += "&_dc=" + (new Date().getTime());
6539 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
6542 cb : "stcCallback"+transId,
6543 scriptId : "stcScript"+transId,
6547 callback : callback,
6553 window[trans.cb] = function(o){
6554 conn.handleResponse(o, trans);
6557 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
6559 if(this.autoAbort !== false){
6563 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
6565 var script = document.createElement("script");
6566 script.setAttribute("src", url);
6567 script.setAttribute("type", "text/javascript");
6568 script.setAttribute("id", trans.scriptId);
6569 this.head.appendChild(script);
6573 callback.call(scope||this, null, arg, false);
6578 isLoading : function(){
6579 return this.trans ? true : false;
6583 * Abort the current server request.
6586 if(this.isLoading()){
6587 this.destroyTrans(this.trans);
6592 destroyTrans : function(trans, isLoaded){
6593 this.head.removeChild(document.getElementById(trans.scriptId));
6594 clearTimeout(trans.timeoutId);
6596 window[trans.cb] = undefined;
6598 delete window[trans.cb];
6601 // if hasn't been loaded, wait for load to remove it to prevent script error
6602 window[trans.cb] = function(){
6603 window[trans.cb] = undefined;
6605 delete window[trans.cb];
6612 handleResponse : function(o, trans){
6614 this.destroyTrans(trans, true);
6617 result = trans.reader.readRecords(o);
6619 this.fireEvent("loadexception", this, o, trans.arg, e);
6620 trans.callback.call(trans.scope||window, null, trans.arg, false);
6623 this.fireEvent("load", this, o, trans.arg);
6624 trans.callback.call(trans.scope||window, result, trans.arg, true);
6628 handleFailure : function(trans){
6630 this.destroyTrans(trans, false);
6631 this.fireEvent("loadexception", this, null, trans.arg);
6632 trans.callback.call(trans.scope||window, null, trans.arg, false);
6636 * Ext JS Library 1.1.1
6637 * Copyright(c) 2006-2007, Ext JS, LLC.
6639 * Originally Released Under LGPL - original licence link has changed is not relivant.
6642 * <script type="text/javascript">
6646 * @class Roo.data.JsonReader
6647 * @extends Roo.data.DataReader
6648 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6649 * based on mappings in a provided Roo.data.Record constructor.
6651 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6652 * in the reply previously.
6657 var RecordDef = Roo.data.Record.create([
6658 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6659 {name: 'occupation'} // This field will use "occupation" as the mapping.
6661 var myReader = new Roo.data.JsonReader({
6662 totalProperty: "results", // The property which contains the total dataset size (optional)
6663 root: "rows", // The property which contains an Array of row objects
6664 id: "id" // The property within each row object that provides an ID for the record (optional)
6668 * This would consume a JSON file like this:
6670 { 'results': 2, 'rows': [
6671 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6672 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6675 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6676 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6677 * paged from the remote server.
6678 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6679 * @cfg {String} root name of the property which contains the Array of row objects.
6680 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6682 * Create a new JsonReader
6683 * @param {Object} meta Metadata configuration options
6684 * @param {Object} recordType Either an Array of field definition objects,
6685 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6687 Roo.data.JsonReader = function(meta, recordType){
6690 // set some defaults:
6692 totalProperty: 'total',
6693 successProperty : 'success',
6698 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6700 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6703 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6704 * Used by Store query builder to append _requestMeta to params.
6707 metaFromRemote : false,
6709 * This method is only used by a DataProxy which has retrieved data from a remote server.
6710 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6711 * @return {Object} data A data block which is used by an Roo.data.Store object as
6712 * a cache of Roo.data.Records.
6714 read : function(response){
6715 var json = response.responseText;
6717 var o = /* eval:var:o */ eval("("+json+")");
6719 throw {message: "JsonReader.read: Json object not found"};
6725 this.metaFromRemote = true;
6726 this.meta = o.metaData;
6727 this.recordType = Roo.data.Record.create(o.metaData.fields);
6728 this.onMetaChange(this.meta, this.recordType, o);
6730 return this.readRecords(o);
6733 // private function a store will implement
6734 onMetaChange : function(meta, recordType, o){
6741 simpleAccess: function(obj, subsc) {
6748 getJsonAccessor: function(){
6750 return function(expr) {
6752 return(re.test(expr))
6753 ? new Function("obj", "return obj." + expr)
6763 * Create a data block containing Roo.data.Records from an XML document.
6764 * @param {Object} o An object which contains an Array of row objects in the property specified
6765 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6766 * which contains the total size of the dataset.
6767 * @return {Object} data A data block which is used by an Roo.data.Store object as
6768 * a cache of Roo.data.Records.
6770 readRecords : function(o){
6772 * After any data loads, the raw JSON data is available for further custom processing.
6776 var s = this.meta, Record = this.recordType,
6777 f = Record.prototype.fields, fi = f.items, fl = f.length;
6779 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6781 if(s.totalProperty) {
6782 this.getTotal = this.getJsonAccessor(s.totalProperty);
6784 if(s.successProperty) {
6785 this.getSuccess = this.getJsonAccessor(s.successProperty);
6787 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6789 var g = this.getJsonAccessor(s.id);
6790 this.getId = function(rec) {
6792 return (r === undefined || r === "") ? null : r;
6795 this.getId = function(){return null;};
6798 for(var jj = 0; jj < fl; jj++){
6800 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6801 this.ef[jj] = this.getJsonAccessor(map);
6805 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6806 if(s.totalProperty){
6807 var vt = parseInt(this.getTotal(o), 10);
6812 if(s.successProperty){
6813 var vs = this.getSuccess(o);
6814 if(vs === false || vs === 'false'){
6819 for(var i = 0; i < c; i++){
6822 var id = this.getId(n);
6823 for(var j = 0; j < fl; j++){
6825 var v = this.ef[j](n);
6827 Roo.log('missing convert for ' + f.name);
6831 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6833 var record = new Record(values, id);
6835 records[i] = record;
6841 totalRecords : totalRecords
6846 * Ext JS Library 1.1.1
6847 * Copyright(c) 2006-2007, Ext JS, LLC.
6849 * Originally Released Under LGPL - original licence link has changed is not relivant.
6852 * <script type="text/javascript">
6856 * @class Roo.data.ArrayReader
6857 * @extends Roo.data.DataReader
6858 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6859 * Each element of that Array represents a row of data fields. The
6860 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6861 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6865 var RecordDef = Roo.data.Record.create([
6866 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6867 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6869 var myReader = new Roo.data.ArrayReader({
6870 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6874 * This would consume an Array like this:
6876 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6878 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6880 * Create a new JsonReader
6881 * @param {Object} meta Metadata configuration options.
6882 * @param {Object} recordType Either an Array of field definition objects
6883 * as specified to {@link Roo.data.Record#create},
6884 * or an {@link Roo.data.Record} object
6885 * created using {@link Roo.data.Record#create}.
6887 Roo.data.ArrayReader = function(meta, recordType){
6888 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6891 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6893 * Create a data block containing Roo.data.Records from an XML document.
6894 * @param {Object} o An Array of row objects which represents the dataset.
6895 * @return {Object} data A data block which is used by an Roo.data.Store object as
6896 * a cache of Roo.data.Records.
6898 readRecords : function(o){
6899 var sid = this.meta ? this.meta.id : null;
6900 var recordType = this.recordType, fields = recordType.prototype.fields;
6903 for(var i = 0; i < root.length; i++){
6906 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6907 for(var j = 0, jlen = fields.length; j < jlen; j++){
6908 var f = fields.items[j];
6909 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6910 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6914 var record = new recordType(values, id);
6916 records[records.length] = record;
6920 totalRecords : records.length
6929 * @class Roo.bootstrap.ComboBox
6930 * @extends Roo.bootstrap.TriggerField
6931 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
6933 * Create a new ComboBox.
6934 * @param {Object} config Configuration options
6936 Roo.bootstrap.ComboBox = function(config){
6937 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
6941 * Fires when the dropdown list is expanded
6942 * @param {Roo.bootstrap.ComboBox} combo This combo box
6947 * Fires when the dropdown list is collapsed
6948 * @param {Roo.bootstrap.ComboBox} combo This combo box
6952 * @event beforeselect
6953 * Fires before a list item is selected. Return false to cancel the selection.
6954 * @param {Roo.bootstrap.ComboBox} combo This combo box
6955 * @param {Roo.data.Record} record The data record returned from the underlying store
6956 * @param {Number} index The index of the selected item in the dropdown list
6958 'beforeselect' : true,
6961 * Fires when a list item is selected
6962 * @param {Roo.bootstrap.ComboBox} combo This combo box
6963 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
6964 * @param {Number} index The index of the selected item in the dropdown list
6968 * @event beforequery
6969 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
6970 * The event object passed has these properties:
6971 * @param {Roo.bootstrap.ComboBox} combo This combo box
6972 * @param {String} query The query
6973 * @param {Boolean} forceAll true to force "all" query
6974 * @param {Boolean} cancel true to cancel the query
6975 * @param {Object} e The query event object
6977 'beforequery': true,
6980 * Fires when the 'add' icon is pressed (add a listener to enable add button)
6981 * @param {Roo.bootstrap.ComboBox} combo This combo box
6986 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
6987 * @param {Roo.bootstrap.ComboBox} combo This combo box
6988 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
6996 this.selectedIndex = -1;
6997 if(this.mode == 'local'){
6998 if(config.queryDelay === undefined){
6999 this.queryDelay = 10;
7001 if(config.minChars === undefined){
7007 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
7010 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
7011 * rendering into an Roo.Editor, defaults to false)
7014 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
7015 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
7018 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
7021 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
7022 * the dropdown list (defaults to undefined, with no header element)
7026 * @cfg {String/Roo.Template} tpl The template to use to render the output
7030 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
7032 listWidth: undefined,
7034 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
7035 * mode = 'remote' or 'text' if mode = 'local')
7037 displayField: undefined,
7039 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
7040 * mode = 'remote' or 'value' if mode = 'local').
7041 * Note: use of a valueField requires the user make a selection
7042 * in order for a value to be mapped.
7044 valueField: undefined,
7048 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
7049 * field's data value (defaults to the underlying DOM element's name)
7051 hiddenName: undefined,
7053 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
7057 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
7059 selectedClass: 'active',
7062 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
7066 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
7067 * anchor positions (defaults to 'tl-bl')
7069 listAlign: 'tl-bl?',
7071 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
7075 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
7076 * query specified by the allQuery config option (defaults to 'query')
7078 triggerAction: 'query',
7080 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
7081 * (defaults to 4, does not apply if editable = false)
7085 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
7086 * delay (typeAheadDelay) if it matches a known value (defaults to false)
7090 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
7091 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
7095 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
7096 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
7100 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
7101 * when editable = true (defaults to false)
7103 selectOnFocus:false,
7105 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
7107 queryParam: 'query',
7109 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
7110 * when mode = 'remote' (defaults to 'Loading...')
7112 loadingText: 'Loading...',
7114 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
7118 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
7122 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
7123 * traditional select (defaults to true)
7127 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
7131 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
7135 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
7136 * listWidth has a higher value)
7140 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
7141 * allow the user to set arbitrary text into the field (defaults to false)
7143 forceSelection:false,
7145 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
7146 * if typeAhead = true (defaults to 250)
7148 typeAheadDelay : 250,
7150 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
7151 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
7153 valueNotFoundText : undefined,
7155 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
7160 * @cfg {Boolean} disableClear Disable showing of clear button.
7162 disableClear : false,
7164 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
7166 alwaysQuery : false,
7172 // element that contains real text value.. (when hidden is used..)
7175 initEvents: function(){
7178 throw "can not find store for combo";
7180 this.store = Roo.factory(this.store, Roo.data);
7184 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
7187 if(this.hiddenName){
7189 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
7191 this.hiddenField.dom.value =
7192 this.hiddenValue !== undefined ? this.hiddenValue :
7193 this.value !== undefined ? this.value : '';
7195 // prevent input submission
7196 this.el.dom.removeAttribute('name');
7197 this.hiddenField.dom.setAttribute('name', this.hiddenName);
7202 // this.el.dom.setAttribute('autocomplete', 'off');
7205 var cls = 'x-combo-list';
7206 this.list = this.el.select('ul',true).first();
7208 //this.list = new Roo.Layer({
7209 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
7212 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
7213 this.list.setWidth(lw);
7215 this.list.on('mouseover', this.onViewOver, this);
7216 this.list.on('mousemove', this.onViewMove, this);
7219 this.list.swallowEvent('mousewheel');
7220 this.assetHeight = 0;
7223 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
7224 this.assetHeight += this.header.getHeight();
7227 this.innerList = this.list.createChild({cls:cls+'-inner'});
7228 this.innerList.on('mouseover', this.onViewOver, this);
7229 this.innerList.on('mousemove', this.onViewMove, this);
7230 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7232 if(this.allowBlank && !this.pageSize && !this.disableClear){
7233 this.footer = this.list.createChild({cls:cls+'-ft'});
7234 this.pageTb = new Roo.Toolbar(this.footer);
7238 this.footer = this.list.createChild({cls:cls+'-ft'});
7239 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
7240 {pageSize: this.pageSize});
7244 if (this.pageTb && this.allowBlank && !this.disableClear) {
7246 this.pageTb.add(new Roo.Toolbar.Fill(), {
7247 cls: 'x-btn-icon x-btn-clear',
7253 _this.onSelect(false, -1);
7258 this.assetHeight += this.footer.getHeight();
7263 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
7266 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
7267 singleSelect:true, store: this.store, selectedClass: this.selectedClass
7269 //this.view.wrapEl.setDisplayed(false);
7270 this.view.on('click', this.onViewClick, this);
7274 this.store.on('beforeload', this.onBeforeLoad, this);
7275 this.store.on('load', this.onLoad, this);
7276 this.store.on('loadexception', this.onLoadException, this);
7279 this.resizer = new Roo.Resizable(this.list, {
7280 pinned:true, handles:'se'
7282 this.resizer.on('resize', function(r, w, h){
7283 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
7285 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
7286 this.restrictHeight();
7288 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
7292 this.editable = true;
7293 this.setEditable(false);
7298 if (typeof(this.events.add.listeners) != 'undefined') {
7300 this.addicon = this.wrap.createChild(
7301 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
7303 this.addicon.on('click', function(e) {
7304 this.fireEvent('add', this);
7307 if (typeof(this.events.edit.listeners) != 'undefined') {
7309 this.editicon = this.wrap.createChild(
7310 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
7312 this.editicon.setStyle('margin-left', '40px');
7314 this.editicon.on('click', function(e) {
7316 // we fire even if inothing is selected..
7317 this.fireEvent('edit', this, this.lastData );
7324 this.keyNav = new Roo.KeyNav(this.inputEl(), {
7326 this.inKeyMode = true;
7330 "down" : function(e){
7331 if(!this.isExpanded()){
7332 this.onTriggerClick();
7334 this.inKeyMode = true;
7339 "enter" : function(e){
7344 "esc" : function(e){
7348 "tab" : function(e){
7351 if(this.fireEvent("specialkey", this, e)){
7352 this.onViewClick(false);
7360 doRelay : function(foo, bar, hname){
7361 if(hname == 'down' || this.scope.isExpanded()){
7362 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
7371 this.queryDelay = Math.max(this.queryDelay || 10,
7372 this.mode == 'local' ? 10 : 250);
7375 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
7378 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
7380 if(this.editable !== false){
7381 this.inputEl().on("keyup", this.onKeyUp, this);
7383 if(this.forceSelection){
7384 this.on('blur', this.doForce, this);
7388 onDestroy : function(){
7390 this.view.setStore(null);
7391 this.view.el.removeAllListeners();
7392 this.view.el.remove();
7393 this.view.purgeListeners();
7396 this.list.dom.innerHTML = '';
7399 this.store.un('beforeload', this.onBeforeLoad, this);
7400 this.store.un('load', this.onLoad, this);
7401 this.store.un('loadexception', this.onLoadException, this);
7403 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
7407 fireKey : function(e){
7408 if(e.isNavKeyPress() && !this.list.isVisible()){
7409 this.fireEvent("specialkey", this, e);
7414 onResize: function(w, h){
7415 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
7417 // if(typeof w != 'number'){
7418 // // we do not handle it!?!?
7421 // var tw = this.trigger.getWidth();
7422 // // tw += this.addicon ? this.addicon.getWidth() : 0;
7423 // // tw += this.editicon ? this.editicon.getWidth() : 0;
7425 // this.inputEl().setWidth( this.adjustWidth('input', x));
7427 // //this.trigger.setStyle('left', x+'px');
7429 // if(this.list && this.listWidth === undefined){
7430 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
7431 // this.list.setWidth(lw);
7432 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7440 * Allow or prevent the user from directly editing the field text. If false is passed,
7441 * the user will only be able to select from the items defined in the dropdown list. This method
7442 * is the runtime equivalent of setting the 'editable' config option at config time.
7443 * @param {Boolean} value True to allow the user to directly edit the field text
7445 setEditable : function(value){
7446 if(value == this.editable){
7449 this.editable = value;
7451 this.inputEl().dom.setAttribute('readOnly', true);
7452 this.inputEl().on('mousedown', this.onTriggerClick, this);
7453 this.inputEl().addClass('x-combo-noedit');
7455 this.inputEl().dom.setAttribute('readOnly', false);
7456 this.inputEl().un('mousedown', this.onTriggerClick, this);
7457 this.inputEl().removeClass('x-combo-noedit');
7462 onBeforeLoad : function(){
7466 //this.innerList.update(this.loadingText ?
7467 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
7468 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
7470 this.restrictHeight();
7471 this.selectedIndex = -1;
7475 onLoad : function(){
7479 if(this.store.getCount() > 0){
7481 this.restrictHeight();
7482 if(this.lastQuery == this.allQuery){
7484 this.inputEl().dom.select();
7486 if(!this.selectByValue(this.value, true)){
7487 this.select(0, true);
7491 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
7492 this.taTask.delay(this.typeAheadDelay);
7496 this.onEmptyResults();
7501 onLoadException : function()
7504 Roo.log(this.store.reader.jsonData);
7505 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7507 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7513 onTypeAhead : function(){
7514 if(this.store.getCount() > 0){
7515 var r = this.store.getAt(0);
7516 var newValue = r.data[this.displayField];
7517 var len = newValue.length;
7518 var selStart = this.getRawValue().length;
7520 if(selStart != len){
7521 this.setRawValue(newValue);
7522 this.selectText(selStart, newValue.length);
7528 onSelect : function(record, index){
7529 if(this.fireEvent('beforeselect', this, record, index) !== false){
7530 this.setFromData(index > -1 ? record.data : false);
7532 this.fireEvent('select', this, record, index);
7537 * Returns the currently selected field value or empty string if no value is set.
7538 * @return {String} value The selected value
7540 getValue : function(){
7541 if(this.valueField){
7542 return typeof this.value != 'undefined' ? this.value : '';
7544 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
7549 * Clears any text/value currently set in the field
7551 clearValue : function(){
7552 if(this.hiddenField){
7553 this.hiddenField.dom.value = '';
7556 this.setRawValue('');
7557 this.lastSelectionText = '';
7562 * Sets the specified value into the field. If the value finds a match, the corresponding record text
7563 * will be displayed in the field. If the value does not match the data value of an existing item,
7564 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
7565 * Otherwise the field will be blank (although the value will still be set).
7566 * @param {String} value The value to match
7568 setValue : function(v){
7570 if(this.valueField){
7571 var r = this.findRecord(this.valueField, v);
7573 text = r.data[this.displayField];
7574 }else if(this.valueNotFoundText !== undefined){
7575 text = this.valueNotFoundText;
7578 this.lastSelectionText = text;
7579 if(this.hiddenField){
7580 this.hiddenField.dom.value = v;
7582 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
7586 * @property {Object} the last set data for the element
7591 * Sets the value of the field based on a object which is related to the record format for the store.
7592 * @param {Object} value the value to set as. or false on reset?
7594 setFromData : function(o){
7595 var dv = ''; // display value
7596 var vv = ''; // value value..
7598 if (this.displayField) {
7599 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
7601 // this is an error condition!!!
7602 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
7605 if(this.valueField){
7606 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
7608 if(this.hiddenField){
7609 this.hiddenField.dom.value = vv;
7611 this.lastSelectionText = dv;
7612 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7616 // no hidden field.. - we store the value in 'value', but still display
7617 // display field!!!!
7618 this.lastSelectionText = dv;
7619 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7626 // overridden so that last data is reset..
7627 this.setValue(this.originalValue);
7628 this.clearInvalid();
7629 this.lastData = false;
7631 this.view.clearSelections();
7635 findRecord : function(prop, value){
7637 if(this.store.getCount() > 0){
7638 this.store.each(function(r){
7639 if(r.data[prop] == value){
7651 // returns hidden if it's set..
7652 if (!this.rendered) {return ''};
7653 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
7657 onViewMove : function(e, t){
7658 this.inKeyMode = false;
7662 onViewOver : function(e, t){
7663 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
7666 var item = this.view.findItemFromChild(t);
7668 var index = this.view.indexOf(item);
7669 this.select(index, false);
7674 onViewClick : function(doFocus)
7676 var index = this.view.getSelectedIndexes()[0];
7677 var r = this.store.getAt(index);
7679 this.onSelect(r, index);
7681 if(doFocus !== false && !this.blockFocus){
7682 this.inputEl().focus();
7687 restrictHeight : function(){
7688 //this.innerList.dom.style.height = '';
7689 //var inner = this.innerList.dom;
7690 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
7691 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
7692 //this.list.beginUpdate();
7693 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
7694 this.list.alignTo(this.inputEl(), this.listAlign);
7695 //this.list.endUpdate();
7699 onEmptyResults : function(){
7704 * Returns true if the dropdown list is expanded, else false.
7706 isExpanded : function(){
7707 return this.list.isVisible();
7711 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
7712 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7713 * @param {String} value The data value of the item to select
7714 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7715 * selected item if it is not currently in view (defaults to true)
7716 * @return {Boolean} True if the value matched an item in the list, else false
7718 selectByValue : function(v, scrollIntoView){
7719 if(v !== undefined && v !== null){
7720 var r = this.findRecord(this.valueField || this.displayField, v);
7722 this.select(this.store.indexOf(r), scrollIntoView);
7730 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
7731 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7732 * @param {Number} index The zero-based index of the list item to select
7733 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7734 * selected item if it is not currently in view (defaults to true)
7736 select : function(index, scrollIntoView){
7737 this.selectedIndex = index;
7738 this.view.select(index);
7739 if(scrollIntoView !== false){
7740 var el = this.view.getNode(index);
7742 //this.innerList.scrollChildIntoView(el, false);
7749 selectNext : function(){
7750 var ct = this.store.getCount();
7752 if(this.selectedIndex == -1){
7754 }else if(this.selectedIndex < ct-1){
7755 this.select(this.selectedIndex+1);
7761 selectPrev : function(){
7762 var ct = this.store.getCount();
7764 if(this.selectedIndex == -1){
7766 }else if(this.selectedIndex != 0){
7767 this.select(this.selectedIndex-1);
7773 onKeyUp : function(e){
7774 if(this.editable !== false && !e.isSpecialKey()){
7775 this.lastKey = e.getKey();
7776 this.dqTask.delay(this.queryDelay);
7781 validateBlur : function(){
7782 return !this.list || !this.list.isVisible();
7786 initQuery : function(){
7787 this.doQuery(this.getRawValue());
7791 doForce : function(){
7792 if(this.el.dom.value.length > 0){
7794 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
7800 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
7801 * query allowing the query action to be canceled if needed.
7802 * @param {String} query The SQL query to execute
7803 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
7804 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
7805 * saved in the current store (defaults to false)
7807 doQuery : function(q, forceAll){
7808 if(q === undefined || q === null){
7817 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
7821 forceAll = qe.forceAll;
7822 if(forceAll === true || (q.length >= this.minChars)){
7823 if(this.lastQuery != q || this.alwaysQuery){
7825 if(this.mode == 'local'){
7826 this.selectedIndex = -1;
7828 this.store.clearFilter();
7830 this.store.filter(this.displayField, q);
7834 this.store.baseParams[this.queryParam] = q;
7836 params: this.getParams(q)
7841 this.selectedIndex = -1;
7848 getParams : function(q){
7850 //p[this.queryParam] = q;
7853 p.limit = this.pageSize;
7859 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
7861 collapse : function(){
7862 if(!this.isExpanded()){
7866 Roo.get(document).un('mousedown', this.collapseIf, this);
7867 Roo.get(document).un('mousewheel', this.collapseIf, this);
7868 if (!this.editable) {
7869 Roo.get(document).un('keydown', this.listKeyPress, this);
7871 this.fireEvent('collapse', this);
7875 collapseIf : function(e){
7876 if(!e.within(this.el) && !e.within(this.el)){
7882 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
7884 expand : function(){
7886 if(this.isExpanded() || !this.hasFocus){
7889 this.list.alignTo(this.inputEl(), this.listAlign);
7891 Roo.get(document).on('mousedown', this.collapseIf, this);
7892 Roo.get(document).on('mousewheel', this.collapseIf, this);
7893 if (!this.editable) {
7894 Roo.get(document).on('keydown', this.listKeyPress, this);
7897 this.fireEvent('expand', this);
7901 // Implements the default empty TriggerField.onTriggerClick function
7902 onTriggerClick : function()
7904 Roo.log('trigger click');
7909 if(this.isExpanded()){
7911 if (!this.blockFocus) {
7912 this.inputEl().focus();
7916 this.hasFocus = true;
7917 if(this.triggerAction == 'all') {
7918 this.doQuery(this.allQuery, true);
7920 this.doQuery(this.getRawValue());
7922 if (!this.blockFocus) {
7923 this.inputEl().focus();
7927 listKeyPress : function(e)
7929 //Roo.log('listkeypress');
7930 // scroll to first matching element based on key pres..
7931 if (e.isSpecialKey()) {
7934 var k = String.fromCharCode(e.getKey()).toUpperCase();
7937 var csel = this.view.getSelectedNodes();
7938 var cselitem = false;
7940 var ix = this.view.indexOf(csel[0]);
7941 cselitem = this.store.getAt(ix);
7942 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
7948 this.store.each(function(v) {
7950 // start at existing selection.
7951 if (cselitem.id == v.id) {
7957 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
7958 match = this.store.indexOf(v);
7964 if (match === false) {
7965 return true; // no more action?
7968 this.view.select(match);
7969 var sn = Roo.get(this.view.getSelectedNodes()[0])
7970 //sn.scrollIntoView(sn.dom.parentNode, false);
7974 * @cfg {Boolean} grow
7978 * @cfg {Number} growMin
7982 * @cfg {Number} growMax
7991 * Ext JS Library 1.1.1
7992 * Copyright(c) 2006-2007, Ext JS, LLC.
7994 * Originally Released Under LGPL - original licence link has changed is not relivant.
7997 * <script type="text/javascript">
8002 * @extends Roo.util.Observable
8003 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
8004 * This class also supports single and multi selection modes. <br>
8005 * Create a data model bound view:
8007 var store = new Roo.data.Store(...);
8009 var view = new Roo.View({
8011 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
8014 selectedClass: "ydataview-selected",
8018 // listen for node click?
8019 view.on("click", function(vw, index, node, e){
8020 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
8024 dataModel.load("foobar.xml");
8026 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
8028 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
8029 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
8031 * Note: old style constructor is still suported (container, template, config)
8035 * @param {Object} config The config object
8038 Roo.View = function(config, depreciated_tpl, depreciated_config){
8040 if (typeof(depreciated_tpl) == 'undefined') {
8041 // new way.. - universal constructor.
8042 Roo.apply(this, config);
8043 this.el = Roo.get(this.el);
8046 this.el = Roo.get(config);
8047 this.tpl = depreciated_tpl;
8048 Roo.apply(this, depreciated_config);
8050 this.wrapEl = this.el.wrap().wrap();
8051 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
8054 if(typeof(this.tpl) == "string"){
8055 this.tpl = new Roo.Template(this.tpl);
8057 // support xtype ctors..
8058 this.tpl = new Roo.factory(this.tpl, Roo);
8070 * @event beforeclick
8071 * Fires before a click is processed. Returns false to cancel the default action.
8072 * @param {Roo.View} this
8073 * @param {Number} index The index of the target node
8074 * @param {HTMLElement} node The target node
8075 * @param {Roo.EventObject} e The raw event object
8077 "beforeclick" : true,
8080 * Fires when a template node is clicked.
8081 * @param {Roo.View} this
8082 * @param {Number} index The index of the target node
8083 * @param {HTMLElement} node The target node
8084 * @param {Roo.EventObject} e The raw event object
8089 * Fires when a template node is double clicked.
8090 * @param {Roo.View} this
8091 * @param {Number} index The index of the target node
8092 * @param {HTMLElement} node The target node
8093 * @param {Roo.EventObject} e The raw event object
8097 * @event contextmenu
8098 * Fires when a template node is right clicked.
8099 * @param {Roo.View} this
8100 * @param {Number} index The index of the target node
8101 * @param {HTMLElement} node The target node
8102 * @param {Roo.EventObject} e The raw event object
8104 "contextmenu" : true,
8106 * @event selectionchange
8107 * Fires when the selected nodes change.
8108 * @param {Roo.View} this
8109 * @param {Array} selections Array of the selected nodes
8111 "selectionchange" : true,
8114 * @event beforeselect
8115 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
8116 * @param {Roo.View} this
8117 * @param {HTMLElement} node The node to be selected
8118 * @param {Array} selections Array of currently selected nodes
8120 "beforeselect" : true,
8122 * @event preparedata
8123 * Fires on every row to render, to allow you to change the data.
8124 * @param {Roo.View} this
8125 * @param {Object} data to be rendered (change this)
8127 "preparedata" : true
8135 "click": this.onClick,
8136 "dblclick": this.onDblClick,
8137 "contextmenu": this.onContextMenu,
8141 this.selections = [];
8143 this.cmp = new Roo.CompositeElementLite([]);
8145 this.store = Roo.factory(this.store, Roo.data);
8146 this.setStore(this.store, true);
8149 if ( this.footer && this.footer.xtype) {
8151 var fctr = this.wrapEl.appendChild(document.createElement("div"));
8153 this.footer.dataSource = this.store
8154 this.footer.container = fctr;
8155 this.footer = Roo.factory(this.footer, Roo);
8156 fctr.insertFirst(this.el);
8158 // this is a bit insane - as the paging toolbar seems to detach the el..
8159 // dom.parentNode.parentNode.parentNode
8160 // they get detached?
8164 Roo.View.superclass.constructor.call(this);
8169 Roo.extend(Roo.View, Roo.util.Observable, {
8172 * @cfg {Roo.data.Store} store Data store to load data from.
8177 * @cfg {String|Roo.Element} el The container element.
8182 * @cfg {String|Roo.Template} tpl The template used by this View
8186 * @cfg {String} dataName the named area of the template to use as the data area
8187 * Works with domtemplates roo-name="name"
8191 * @cfg {String} selectedClass The css class to add to selected nodes
8193 selectedClass : "x-view-selected",
8195 * @cfg {String} emptyText The empty text to show when nothing is loaded.
8200 * @cfg {String} text to display on mask (default Loading)
8204 * @cfg {Boolean} multiSelect Allow multiple selection
8206 multiSelect : false,
8208 * @cfg {Boolean} singleSelect Allow single selection
8210 singleSelect: false,
8213 * @cfg {Boolean} toggleSelect - selecting
8215 toggleSelect : false,
8218 * Returns the element this view is bound to.
8219 * @return {Roo.Element}
8228 * Refreshes the view. - called by datachanged on the store. - do not call directly.
8230 refresh : function(){
8233 // if we are using something like 'domtemplate', then
8234 // the what gets used is:
8235 // t.applySubtemplate(NAME, data, wrapping data..)
8236 // the outer template then get' applied with
8237 // the store 'extra data'
8238 // and the body get's added to the
8239 // roo-name="data" node?
8240 // <span class='roo-tpl-{name}'></span> ?????
8244 this.clearSelections();
8247 var records = this.store.getRange();
8248 if(records.length < 1) {
8250 // is this valid?? = should it render a template??
8252 this.el.update(this.emptyText);
8256 if (this.dataName) {
8257 this.el.update(t.apply(this.store.meta)); //????
8258 el = this.el.child('.roo-tpl-' + this.dataName);
8261 for(var i = 0, len = records.length; i < len; i++){
8262 var data = this.prepareData(records[i].data, i, records[i]);
8263 this.fireEvent("preparedata", this, data, i, records[i]);
8264 html[html.length] = Roo.util.Format.trim(
8266 t.applySubtemplate(this.dataName, data, this.store.meta) :
8273 el.update(html.join(""));
8274 this.nodes = el.dom.childNodes;
8275 this.updateIndexes(0);
8279 * Function to override to reformat the data that is sent to
8280 * the template for each node.
8281 * DEPRICATED - use the preparedata event handler.
8282 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
8283 * a JSON object for an UpdateManager bound view).
8285 prepareData : function(data, index, record)
8287 this.fireEvent("preparedata", this, data, index, record);
8291 onUpdate : function(ds, record){
8292 this.clearSelections();
8293 var index = this.store.indexOf(record);
8294 var n = this.nodes[index];
8295 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
8296 n.parentNode.removeChild(n);
8297 this.updateIndexes(index, index);
8303 onAdd : function(ds, records, index)
8305 this.clearSelections();
8306 if(this.nodes.length == 0){
8310 var n = this.nodes[index];
8311 for(var i = 0, len = records.length; i < len; i++){
8312 var d = this.prepareData(records[i].data, i, records[i]);
8314 this.tpl.insertBefore(n, d);
8317 this.tpl.append(this.el, d);
8320 this.updateIndexes(index);
8323 onRemove : function(ds, record, index){
8324 this.clearSelections();
8325 var el = this.dataName ?
8326 this.el.child('.roo-tpl-' + this.dataName) :
8328 el.dom.removeChild(this.nodes[index]);
8329 this.updateIndexes(index);
8333 * Refresh an individual node.
8334 * @param {Number} index
8336 refreshNode : function(index){
8337 this.onUpdate(this.store, this.store.getAt(index));
8340 updateIndexes : function(startIndex, endIndex){
8341 var ns = this.nodes;
8342 startIndex = startIndex || 0;
8343 endIndex = endIndex || ns.length - 1;
8344 for(var i = startIndex; i <= endIndex; i++){
8345 ns[i].nodeIndex = i;
8350 * Changes the data store this view uses and refresh the view.
8351 * @param {Store} store
8353 setStore : function(store, initial){
8354 if(!initial && this.store){
8355 this.store.un("datachanged", this.refresh);
8356 this.store.un("add", this.onAdd);
8357 this.store.un("remove", this.onRemove);
8358 this.store.un("update", this.onUpdate);
8359 this.store.un("clear", this.refresh);
8360 this.store.un("beforeload", this.onBeforeLoad);
8361 this.store.un("load", this.onLoad);
8362 this.store.un("loadexception", this.onLoad);
8366 store.on("datachanged", this.refresh, this);
8367 store.on("add", this.onAdd, this);
8368 store.on("remove", this.onRemove, this);
8369 store.on("update", this.onUpdate, this);
8370 store.on("clear", this.refresh, this);
8371 store.on("beforeload", this.onBeforeLoad, this);
8372 store.on("load", this.onLoad, this);
8373 store.on("loadexception", this.onLoad, this);
8381 * onbeforeLoad - masks the loading area.
8384 onBeforeLoad : function()
8387 this.el.mask(this.mask ? this.mask : "Loading" );
8389 onLoad : function ()
8396 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
8397 * @param {HTMLElement} node
8398 * @return {HTMLElement} The template node
8400 findItemFromChild : function(node){
8401 var el = this.dataName ?
8402 this.el.child('.roo-tpl-' + this.dataName,true) :
8405 if(!node || node.parentNode == el){
8408 var p = node.parentNode;
8409 while(p && p != el){
8410 if(p.parentNode == el){
8419 onClick : function(e){
8420 var item = this.findItemFromChild(e.getTarget());
8422 var index = this.indexOf(item);
8423 if(this.onItemClick(item, index, e) !== false){
8424 this.fireEvent("click", this, index, item, e);
8427 this.clearSelections();
8432 onContextMenu : function(e){
8433 var item = this.findItemFromChild(e.getTarget());
8435 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
8440 onDblClick : function(e){
8441 var item = this.findItemFromChild(e.getTarget());
8443 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
8447 onItemClick : function(item, index, e)
8449 if(this.fireEvent("beforeclick", this, index, item, e) === false){
8452 if (this.toggleSelect) {
8453 var m = this.isSelected(item) ? 'unselect' : 'select';
8456 _t[m](item, true, false);
8459 if(this.multiSelect || this.singleSelect){
8460 if(this.multiSelect && e.shiftKey && this.lastSelection){
8461 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
8463 this.select(item, this.multiSelect && e.ctrlKey);
8464 this.lastSelection = item;
8472 * Get the number of selected nodes.
8475 getSelectionCount : function(){
8476 return this.selections.length;
8480 * Get the currently selected nodes.
8481 * @return {Array} An array of HTMLElements
8483 getSelectedNodes : function(){
8484 return this.selections;
8488 * Get the indexes of the selected nodes.
8491 getSelectedIndexes : function(){
8492 var indexes = [], s = this.selections;
8493 for(var i = 0, len = s.length; i < len; i++){
8494 indexes.push(s[i].nodeIndex);
8500 * Clear all selections
8501 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
8503 clearSelections : function(suppressEvent){
8504 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
8505 this.cmp.elements = this.selections;
8506 this.cmp.removeClass(this.selectedClass);
8507 this.selections = [];
8509 this.fireEvent("selectionchange", this, this.selections);
8515 * Returns true if the passed node is selected
8516 * @param {HTMLElement/Number} node The node or node index
8519 isSelected : function(node){
8520 var s = this.selections;
8524 node = this.getNode(node);
8525 return s.indexOf(node) !== -1;
8530 * @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
8531 * @param {Boolean} keepExisting (optional) true to keep existing selections
8532 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8534 select : function(nodeInfo, keepExisting, suppressEvent){
8535 if(nodeInfo instanceof Array){
8537 this.clearSelections(true);
8539 for(var i = 0, len = nodeInfo.length; i < len; i++){
8540 this.select(nodeInfo[i], true, true);
8544 var node = this.getNode(nodeInfo);
8545 if(!node || this.isSelected(node)){
8546 return; // already selected.
8549 this.clearSelections(true);
8551 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
8552 Roo.fly(node).addClass(this.selectedClass);
8553 this.selections.push(node);
8555 this.fireEvent("selectionchange", this, this.selections);
8563 * @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
8564 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
8565 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8567 unselect : function(nodeInfo, keepExisting, suppressEvent)
8569 if(nodeInfo instanceof Array){
8570 Roo.each(this.selections, function(s) {
8571 this.unselect(s, nodeInfo);
8575 var node = this.getNode(nodeInfo);
8576 if(!node || !this.isSelected(node)){
8577 Roo.log("not selected");
8578 return; // not selected.
8582 Roo.each(this.selections, function(s) {
8584 Roo.fly(node).removeClass(this.selectedClass);
8591 this.selections= ns;
8592 this.fireEvent("selectionchange", this, this.selections);
8596 * Gets a template node.
8597 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8598 * @return {HTMLElement} The node or null if it wasn't found
8600 getNode : function(nodeInfo){
8601 if(typeof nodeInfo == "string"){
8602 return document.getElementById(nodeInfo);
8603 }else if(typeof nodeInfo == "number"){
8604 return this.nodes[nodeInfo];
8610 * Gets a range template nodes.
8611 * @param {Number} startIndex
8612 * @param {Number} endIndex
8613 * @return {Array} An array of nodes
8615 getNodes : function(start, end){
8616 var ns = this.nodes;
8618 end = typeof end == "undefined" ? ns.length - 1 : end;
8621 for(var i = start; i <= end; i++){
8625 for(var i = start; i >= end; i--){
8633 * Finds the index of the passed node
8634 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8635 * @return {Number} The index of the node or -1
8637 indexOf : function(node){
8638 node = this.getNode(node);
8639 if(typeof node.nodeIndex == "number"){
8640 return node.nodeIndex;
8642 var ns = this.nodes;
8643 for(var i = 0, len = ns.length; i < len; i++){
8654 * based on jquery fullcalendar
8658 Roo.bootstrap = Roo.bootstrap || {};
8660 * @class Roo.bootstrap.Calendar
8661 * @extends Roo.bootstrap.Component
8662 * Bootstrap Calendar class
8663 * @cfg {Boolean} loadMask (true|false) default false
8666 * Create a new Container
8667 * @param {Object} config The config object
8672 Roo.bootstrap.Calendar = function(config){
8673 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
8677 * Fires when a date is selected
8678 * @param {DatePicker} this
8679 * @param {Date} date The selected date
8683 * @event monthchange
8684 * Fires when the displayed month changes
8685 * @param {DatePicker} this
8686 * @param {Date} date The selected month
8688 'monthchange': true,
8691 * Fires when mouse over an event
8692 * @param {Calendar} this
8693 * @param {event} Event
8698 * Fires when the mouse leaves an
8699 * @param {Calendar} this
8705 * Fires when the mouse click an
8706 * @param {Calendar} this
8715 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
8718 * @cfg {Number} startDay
8719 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
8725 getAutoCreate : function(){
8728 var fc_button = function(name, corner, style, content ) {
8729 return Roo.apply({},{
8731 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
8733 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
8736 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
8744 style : 'width:100%',
8751 cls : 'fc-header-left',
8753 fc_button('prev', 'left', 'arrow', '‹' ),
8754 fc_button('next', 'right', 'arrow', '›' ),
8755 { tag: 'span', cls: 'fc-header-space' },
8756 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
8764 cls : 'fc-header-center',
8768 cls: 'fc-header-title',
8771 html : 'month / year'
8779 cls : 'fc-header-right',
8781 /* fc_button('month', 'left', '', 'month' ),
8782 fc_button('week', '', '', 'week' ),
8783 fc_button('day', 'right', '', 'day' )
8795 var cal_heads = function() {
8797 // fixme - handle this.
8799 for (var i =0; i < Date.dayNames.length; i++) {
8800 var d = Date.dayNames[i];
8803 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
8804 html : d.substring(0,3)
8808 ret[0].cls += ' fc-first';
8809 ret[6].cls += ' fc-last';
8812 var cal_cell = function(n) {
8815 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
8820 cls: 'fc-day-number',
8824 cls: 'fc-day-content',
8828 style: 'position: relative;' // height: 17px;
8840 var cal_rows = function() {
8843 for (var r = 0; r < 6; r++) {
8850 for (var i =0; i < Date.dayNames.length; i++) {
8851 var d = Date.dayNames[i];
8852 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
8855 row.cn[0].cls+=' fc-first';
8856 row.cn[0].cn[0].style = 'min-height:90px';
8857 row.cn[6].cls+=' fc-last';
8861 ret[0].cls += ' fc-first';
8862 ret[4].cls += ' fc-prev-last';
8863 ret[5].cls += ' fc-last';
8870 cls: 'fc-border-separate',
8871 style : 'width:100%',
8879 cls : 'fc-first fc-last',
8898 style : "position: relative;",
8901 cls : 'fc-view fc-view-month fc-grid',
8902 style : 'position: relative',
8903 unselectable : 'on',
8906 cls : 'fc-event-container',
8907 style : 'position:absolute;z-index:8;top:0;left:0;'
8925 initEvents : function()
8928 throw "can not find store for calendar";
8934 style: "text-align:center",
8938 style: "background-color:white;width:50%;margin:250 auto",
8942 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
8953 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
8955 var size = this.el.select('.fc-content', true).first().getSize();
8956 this.maskEl.setSize(size.width, size.height);
8957 this.maskEl.enableDisplayMode("block");
8962 this.store = Roo.factory(this.store, Roo.data);
8963 this.store.on('load', this.onLoad, this);
8964 this.store.on('beforeload', this.onBeforeLoad, this);
8968 this.cells = this.el.select('.fc-day',true);
8969 //Roo.log(this.cells);
8970 this.textNodes = this.el.query('.fc-day-number');
8971 this.cells.addClassOnOver('fc-state-hover');
8973 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
8974 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
8975 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
8976 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
8978 this.on('monthchange', this.onMonthChange, this);
8980 this.update(new Date().clearTime());
8983 resize : function() {
8984 var sz = this.el.getSize();
8986 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
8987 this.el.select('.fc-day-content div',true).setHeight(34);
8992 showPrevMonth : function(e){
8993 this.update(this.activeDate.add("mo", -1));
8995 showToday : function(e){
8996 this.update(new Date().clearTime());
8999 showNextMonth : function(e){
9000 this.update(this.activeDate.add("mo", 1));
9004 showPrevYear : function(){
9005 this.update(this.activeDate.add("y", -1));
9009 showNextYear : function(){
9010 this.update(this.activeDate.add("y", 1));
9015 update : function(date)
9017 var vd = this.activeDate;
9018 this.activeDate = date;
9019 // if(vd && this.el){
9020 // var t = date.getTime();
9021 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
9022 // Roo.log('using add remove');
9024 // this.fireEvent('monthchange', this, date);
9026 // this.cells.removeClass("fc-state-highlight");
9027 // this.cells.each(function(c){
9028 // if(c.dateValue == t){
9029 // c.addClass("fc-state-highlight");
9030 // setTimeout(function(){
9031 // try{c.dom.firstChild.focus();}catch(e){}
9041 var days = date.getDaysInMonth();
9043 var firstOfMonth = date.getFirstDateOfMonth();
9044 var startingPos = firstOfMonth.getDay()-this.startDay;
9046 if(startingPos < this.startDay){
9050 var pm = date.add(Date.MONTH, -1);
9051 var prevStart = pm.getDaysInMonth()-startingPos;
9053 this.cells = this.el.select('.fc-day',true);
9054 this.textNodes = this.el.query('.fc-day-number');
9055 this.cells.addClassOnOver('fc-state-hover');
9057 var cells = this.cells.elements;
9058 var textEls = this.textNodes;
9060 Roo.each(cells, function(cell){
9061 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
9064 days += startingPos;
9066 // convert everything to numbers so it's fast
9068 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
9071 //Roo.log(prevStart);
9073 var today = new Date().clearTime().getTime();
9074 var sel = date.clearTime().getTime();
9075 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
9076 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
9077 var ddMatch = this.disabledDatesRE;
9078 var ddText = this.disabledDatesText;
9079 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
9080 var ddaysText = this.disabledDaysText;
9081 var format = this.format;
9083 var setCellClass = function(cal, cell){
9085 //Roo.log('set Cell Class');
9087 var t = d.getTime();
9093 cell.className += " fc-today";
9094 cell.className += " fc-state-highlight";
9095 cell.title = cal.todayText;
9098 // disable highlight in other month..
9099 //cell.className += " fc-state-highlight";
9104 cell.className = " fc-state-disabled";
9105 cell.title = cal.minText;
9109 cell.className = " fc-state-disabled";
9110 cell.title = cal.maxText;
9114 if(ddays.indexOf(d.getDay()) != -1){
9115 cell.title = ddaysText;
9116 cell.className = " fc-state-disabled";
9119 if(ddMatch && format){
9120 var fvalue = d.dateFormat(format);
9121 if(ddMatch.test(fvalue)){
9122 cell.title = ddText.replace("%0", fvalue);
9123 cell.className = " fc-state-disabled";
9127 if (!cell.initialClassName) {
9128 cell.initialClassName = cell.dom.className;
9131 cell.dom.className = cell.initialClassName + ' ' + cell.className;
9136 for(; i < startingPos; i++) {
9137 textEls[i].innerHTML = (++prevStart);
9138 d.setDate(d.getDate()+1);
9140 cells[i].className = "fc-past fc-other-month";
9141 setCellClass(this, cells[i]);
9146 for(; i < days; i++){
9147 intDay = i - startingPos + 1;
9148 textEls[i].innerHTML = (intDay);
9149 d.setDate(d.getDate()+1);
9151 cells[i].className = ''; // "x-date-active";
9152 setCellClass(this, cells[i]);
9156 for(; i < 42; i++) {
9157 textEls[i].innerHTML = (++extraDays);
9158 d.setDate(d.getDate()+1);
9160 cells[i].className = "fc-future fc-other-month";
9161 setCellClass(this, cells[i]);
9164 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
9166 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
9168 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
9169 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
9172 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
9173 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
9176 this.fireEvent('monthchange', this, date);
9180 if(!this.internalRender){
9181 var main = this.el.dom.firstChild;
9182 var w = main.offsetWidth;
9183 this.el.setWidth(w + this.el.getBorderWidth("lr"));
9184 Roo.fly(main).setWidth(w);
9185 this.internalRender = true;
9186 // opera does not respect the auto grow header center column
9187 // then, after it gets a width opera refuses to recalculate
9188 // without a second pass
9189 if(Roo.isOpera && !this.secondPass){
9190 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
9191 this.secondPass = true;
9192 this.update.defer(10, this, [date]);
9199 findCell : function(dt) {
9200 dt = dt.clearTime().getTime();
9202 this.cells.each(function(c){
9203 //Roo.log("check " +c.dateValue + '?=' + dt);
9204 if(c.dateValue == dt){
9214 findCells : function(ev) {
9215 var s = ev.start.clone().clearTime().getTime();
9217 var e= ev.end.clone().clearTime().getTime();
9220 this.cells.each(function(c){
9221 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
9223 if(c.dateValue > e){
9226 if(c.dateValue < s){
9235 findBestRow: function(cells)
9239 for (var i =0 ; i < cells.length;i++) {
9240 ret = Math.max(cells[i].rows || 0,ret);
9247 addItem : function(ev)
9249 // look for vertical location slot in
9250 var cells = this.findCells(ev);
9252 ev.row = this.findBestRow(cells);
9254 // work out the location.
9258 for(var i =0; i < cells.length; i++) {
9266 if (crow.start.getY() == cells[i].getY()) {
9268 crow.end = cells[i];
9284 for (var i = 0; i < cells.length;i++) {
9285 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
9289 this.calevents.push(ev);
9292 clearEvents: function() {
9294 if(!this.calevents){
9298 Roo.each(this.cells.elements, function(c){
9302 Roo.each(this.calevents, function(e) {
9303 Roo.each(e.els, function(el) {
9304 el.un('mouseenter' ,this.onEventEnter, this);
9305 el.un('mouseleave' ,this.onEventLeave, this);
9312 renderEvents: function()
9314 // first make sure there is enough space..
9316 this.cells.each(function(c) {
9318 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
9321 for (var e = 0; e < this.calevents.length; e++) {
9322 var ev = this.calevents[e];
9323 var cells = ev.cells;
9326 for(var i =0; i < rows.length; i++) {
9329 // how many rows should it span..
9332 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
9333 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
9335 unselectable : "on",
9338 cls: 'fc-event-inner',
9342 cls: 'fc-event-time',
9343 html : cells.length > 1 ? '' : ev.time
9347 cls: 'fc-event-title',
9348 html : String.format('{0}', ev.title)
9355 cls: 'ui-resizable-handle ui-resizable-e',
9356 html : '  '
9362 cfg.cls += ' fc-event-start';
9364 if ((i+1) == rows.length) {
9365 cfg.cls += ' fc-event-end';
9368 var ctr = this.el.select('.fc-event-container',true).first();
9369 var cg = ctr.createChild(cfg);
9371 cg.on('mouseenter' ,this.onEventEnter, this, ev);
9372 cg.on('mouseleave' ,this.onEventLeave, this, ev);
9373 cg.on('click', this.onEventClick, this, ev);
9377 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
9378 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
9380 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
9381 cg.setWidth(ebox.right - sbox.x -2);
9389 onEventEnter: function (e, el,event,d) {
9390 this.fireEvent('evententer', this, el, event);
9393 onEventLeave: function (e, el,event,d) {
9394 this.fireEvent('eventleave', this, el, event);
9397 onEventClick: function (e, el,event,d) {
9398 this.fireEvent('eventclick', this, el, event);
9401 onMonthChange: function () {
9407 this.calevents = [];
9409 if(this.store.getCount() > 0){
9410 this.store.data.each(function(d){
9413 start: new Date(d.data.start_dt),
9414 end : new Date(d.data.end_dt),
9415 time : d.data.start_time,
9416 title : d.data.title,
9417 description : d.data.description,
9418 venue : d.data.venue
9423 this.renderEvents();
9430 onBeforeLoad: function()
9449 * @class Roo.bootstrap.Popover
9450 * @extends Roo.bootstrap.Component
9451 * Bootstrap Popover class
9452 * @cfg {String} html contents of the popover (or false to use children..)
9453 * @cfg {String} title of popover (or false to hide)
9454 * @cfg {String} placement how it is placed
9455 * @cfg {String} trigger click || hover (or false to trigger manually)
9456 * @cfg {String} over what (parent or false to trigger manually.)
9459 * Create a new Popover
9460 * @param {Object} config The config object
9463 Roo.bootstrap.Popover = function(config){
9464 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
9467 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
9469 title: 'Fill in a title',
9472 placement : 'right',
9473 trigger : 'hover', // hover
9477 can_build_overlaid : false,
9479 getChildContainer : function()
9481 return this.el.select('.popover-content',true).first();
9484 getAutoCreate : function(){
9485 Roo.log('make popover?');
9487 cls : 'popover roo-dynamic',
9488 style: 'display:block',
9494 cls : 'popover-inner',
9498 cls: 'popover-title',
9502 cls : 'popover-content',
9513 setTitle: function(str)
9515 this.el.select('.popover-title',true).first().dom.innerHTML = str;
9517 setContent: function(str)
9519 this.el.select('.popover-content',true).first().dom.innerHTML = str;
9521 // as it get's added to the bottom of the page.
9522 onRender : function(ct, position)
9524 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
9526 var cfg = Roo.apply({}, this.getAutoCreate());
9530 cfg.cls += ' ' + this.cls;
9533 cfg.style = this.style;
9535 Roo.log("adding to ")
9536 this.el = Roo.get(document.body).createChild(cfg, position);
9542 initEvents : function()
9544 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
9545 this.el.enableDisplayMode('block');
9547 if (this.over === false) {
9550 if (this.triggers === false) {
9553 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9554 var triggers = this.trigger ? this.trigger.split(' ') : [];
9555 Roo.each(triggers, function(trigger) {
9557 if (trigger == 'click') {
9558 on_el.on('click', this.toggle, this);
9559 } else if (trigger != 'manual') {
9560 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
9561 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
9563 on_el.on(eventIn ,this.enter, this);
9564 on_el.on(eventOut, this.leave, this);
9575 toggle : function () {
9576 this.hoverState == 'in' ? this.leave() : this.enter();
9579 enter : function () {
9582 clearTimeout(this.timeout);
9584 this.hoverState = 'in'
9586 if (!this.delay || !this.delay.show) {
9591 this.timeout = setTimeout(function () {
9592 if (_t.hoverState == 'in') {
9597 leave : function() {
9598 clearTimeout(this.timeout);
9600 this.hoverState = 'out'
9602 if (!this.delay || !this.delay.hide) {
9607 this.timeout = setTimeout(function () {
9608 if (_t.hoverState == 'out') {
9614 show : function (on_el)
9617 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9620 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
9621 if (this.html !== false) {
9622 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
9624 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
9625 if (!this.title.length) {
9626 this.el.select('.popover-title',true).hide();
9629 var placement = typeof this.placement == 'function' ?
9630 this.placement.call(this, this.el, on_el) :
9633 var autoToken = /\s?auto?\s?/i;
9634 var autoPlace = autoToken.test(placement);
9636 placement = placement.replace(autoToken, '') || 'top';
9640 //this.el.setXY([0,0]);
9642 this.el.dom.style.display='block';
9643 this.el.addClass(placement);
9645 //this.el.appendTo(on_el);
9647 var p = this.getPosition();
9648 var box = this.el.getBox();
9653 var align = Roo.bootstrap.Popover.alignment[placement]
9654 this.el.alignTo(on_el, align[0],align[1]);
9655 //var arrow = this.el.select('.arrow',true).first();
9656 //arrow.set(align[2],
9658 this.el.addClass('in');
9659 this.hoverState = null;
9661 if (this.el.hasClass('fade')) {
9668 this.el.setXY([0,0]);
9669 this.el.removeClass('in');
9676 Roo.bootstrap.Popover.alignment = {
9677 'left' : ['r-l', [-10,0], 'right'],
9678 'right' : ['l-r', [10,0], 'left'],
9679 'bottom' : ['t-b', [0,10], 'top'],
9680 'top' : [ 'b-t', [0,-10], 'bottom']
9691 * @class Roo.bootstrap.Progress
9692 * @extends Roo.bootstrap.Component
9693 * Bootstrap Progress class
9694 * @cfg {Boolean} striped striped of the progress bar
9695 * @cfg {Boolean} active animated of the progress bar
9699 * Create a new Progress
9700 * @param {Object} config The config object
9703 Roo.bootstrap.Progress = function(config){
9704 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
9707 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
9712 getAutoCreate : function(){
9720 cfg.cls += ' progress-striped';
9724 cfg.cls += ' active';
9743 * @class Roo.bootstrap.ProgressBar
9744 * @extends Roo.bootstrap.Component
9745 * Bootstrap ProgressBar class
9746 * @cfg {Number} aria_valuenow aria-value now
9747 * @cfg {Number} aria_valuemin aria-value min
9748 * @cfg {Number} aria_valuemax aria-value max
9749 * @cfg {String} label label for the progress bar
9750 * @cfg {String} panel (success | info | warning | danger )
9751 * @cfg {String} role role of the progress bar
9752 * @cfg {String} sr_only text
9756 * Create a new ProgressBar
9757 * @param {Object} config The config object
9760 Roo.bootstrap.ProgressBar = function(config){
9761 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
9764 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
9768 aria_valuemax : 100,
9774 getAutoCreate : function()
9779 cls: 'progress-bar',
9780 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
9792 cfg.role = this.role;
9795 if(this.aria_valuenow){
9796 cfg['aria-valuenow'] = this.aria_valuenow;
9799 if(this.aria_valuemin){
9800 cfg['aria-valuemin'] = this.aria_valuemin;
9803 if(this.aria_valuemax){
9804 cfg['aria-valuemax'] = this.aria_valuemax;
9807 if(this.label && !this.sr_only){
9808 cfg.html = this.label;
9812 cfg.cls += ' progress-bar-' + this.panel;
9818 update : function(aria_valuenow)
9820 this.aria_valuenow = aria_valuenow;
9822 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
9837 * @class Roo.bootstrap.TabPanel
9838 * @extends Roo.bootstrap.Component
9839 * Bootstrap TabPanel class
9840 * @cfg {Boolean} active panel active
9841 * @cfg {String} html panel content
9842 * @cfg {String} tabId tab relate id
9846 * Create a new TabPanel
9847 * @param {Object} config The config object
9850 Roo.bootstrap.TabPanel = function(config){
9851 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
9854 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
9860 getAutoCreate : function(){
9864 html: this.html || ''
9868 cfg.cls += ' active';
9872 cfg.tabId = this.tabId;
9890 * @class Roo.bootstrap.DateField
9891 * @extends Roo.bootstrap.Input
9892 * Bootstrap DateField class
9893 * @cfg {Number} weekStart default 0
9894 * @cfg {Number} weekStart default 0
9895 * @cfg {Number} viewMode default empty, (months|years)
9896 * @cfg {Number} minViewMode default empty, (months|years)
9897 * @cfg {Number} startDate default -Infinity
9898 * @cfg {Number} endDate default Infinity
9899 * @cfg {Boolean} todayHighlight default false
9900 * @cfg {Boolean} todayBtn default false
9901 * @cfg {Boolean} calendarWeeks default false
9902 * @cfg {Object} daysOfWeekDisabled default empty
9904 * @cfg {Boolean} keyboardNavigation default true
9905 * @cfg {String} language default en
9908 * Create a new DateField
9909 * @param {Object} config The config object
9912 Roo.bootstrap.DateField = function(config){
9913 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
9916 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
9919 * @cfg {String} format
9920 * The default date format string which can be overriden for localization support. The format must be
9921 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
9925 * @cfg {String} altFormats
9926 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
9927 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
9929 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
9937 todayHighlight : false,
9943 keyboardNavigation: true,
9945 calendarWeeks: false,
9947 startDate: -Infinity,
9951 daysOfWeekDisabled: [],
9957 return new Date(Date.UTC.apply(Date, arguments));
9960 UTCToday: function()
9962 var today = new Date();
9963 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
9966 getDate: function() {
9967 var d = this.getUTCDate();
9968 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
9971 getUTCDate: function() {
9975 setDate: function(d) {
9976 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
9979 setUTCDate: function(d) {
9981 this.setValue(this.formatDate(this.date));
9984 onRender: function(ct, position)
9987 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
9989 this.language = this.language || 'en';
9990 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
9991 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
9993 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
9994 this.format = this.format || 'm/d/y';
9995 this.isInline = false;
9996 this.isInput = true;
9997 this.component = this.el.select('.add-on', true).first() || false;
9998 this.component = (this.component && this.component.length === 0) ? false : this.component;
9999 this.hasInput = this.component && this.inputEL().length;
10001 if (typeof(this.minViewMode === 'string')) {
10002 switch (this.minViewMode) {
10004 this.minViewMode = 1;
10007 this.minViewMode = 2;
10010 this.minViewMode = 0;
10015 if (typeof(this.viewMode === 'string')) {
10016 switch (this.viewMode) {
10029 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
10031 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10033 this.picker().on('mousedown', this.onMousedown, this);
10034 this.picker().on('click', this.onClick, this);
10036 this.picker().addClass('datepicker-dropdown');
10038 this.startViewMode = this.viewMode;
10041 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
10042 if(!this.calendarWeeks){
10047 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
10048 v.attr('colspan', function(i, val){
10049 return parseInt(val) + 1;
10054 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
10056 this.setStartDate(this.startDate);
10057 this.setEndDate(this.endDate);
10059 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
10066 if(this.isInline) {
10071 picker : function()
10073 return this.el.select('.datepicker', true).first();
10076 fillDow: function()
10078 var dowCnt = this.weekStart;
10087 if(this.calendarWeeks){
10095 while (dowCnt < this.weekStart + 7) {
10099 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
10103 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
10106 fillMonths: function()
10109 var months = this.picker().select('>.datepicker-months td', true).first();
10111 months.dom.innerHTML = '';
10117 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
10120 months.createChild(month);
10125 update: function(){
10127 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
10129 if (this.date < this.startDate) {
10130 this.viewDate = new Date(this.startDate);
10131 } else if (this.date > this.endDate) {
10132 this.viewDate = new Date(this.endDate);
10134 this.viewDate = new Date(this.date);
10141 var d = new Date(this.viewDate),
10142 year = d.getUTCFullYear(),
10143 month = d.getUTCMonth(),
10144 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
10145 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
10146 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
10147 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
10148 currentDate = this.date && this.date.valueOf(),
10149 today = this.UTCToday();
10151 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
10153 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
10155 // this.picker.select('>tfoot th.today').
10156 // .text(dates[this.language].today)
10157 // .toggle(this.todayBtn !== false);
10159 this.updateNavArrows();
10162 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
10164 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
10166 prevMonth.setUTCDate(day);
10168 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
10170 var nextMonth = new Date(prevMonth);
10172 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
10174 nextMonth = nextMonth.valueOf();
10176 var fillMonths = false;
10178 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
10180 while(prevMonth.valueOf() < nextMonth) {
10183 if (prevMonth.getUTCDay() === this.weekStart) {
10185 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
10193 if(this.calendarWeeks){
10194 // ISO 8601: First week contains first thursday.
10195 // ISO also states week starts on Monday, but we can be more abstract here.
10197 // Start of current week: based on weekstart/current date
10198 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
10199 // Thursday of this week
10200 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
10201 // First Thursday of year, year from thursday
10202 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
10203 // Calendar week: ms between thursdays, div ms per day, div 7 days
10204 calWeek = (th - yth) / 864e5 / 7 + 1;
10206 fillMonths.cn.push({
10214 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
10216 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
10219 if (this.todayHighlight &&
10220 prevMonth.getUTCFullYear() == today.getFullYear() &&
10221 prevMonth.getUTCMonth() == today.getMonth() &&
10222 prevMonth.getUTCDate() == today.getDate()) {
10223 clsName += ' today';
10226 if (currentDate && prevMonth.valueOf() === currentDate) {
10227 clsName += ' active';
10230 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
10231 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
10232 clsName += ' disabled';
10235 fillMonths.cn.push({
10237 cls: 'day ' + clsName,
10238 html: prevMonth.getDate()
10241 prevMonth.setDate(prevMonth.getDate()+1);
10244 var currentYear = this.date && this.date.getUTCFullYear();
10245 var currentMonth = this.date && this.date.getUTCMonth();
10247 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
10249 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
10250 v.removeClass('active');
10252 if(currentYear === year && k === currentMonth){
10253 v.addClass('active');
10256 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
10257 v.addClass('disabled');
10263 year = parseInt(year/10, 10) * 10;
10265 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
10267 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
10270 for (var i = -1; i < 11; i++) {
10271 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
10273 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
10281 showMode: function(dir) {
10283 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
10285 Roo.each(this.picker().select('>div',true).elements, function(v){
10286 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10289 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
10294 if(this.isInline) return;
10296 this.picker().removeClass(['bottom', 'top']);
10298 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
10300 * place to the top of element!
10304 this.picker().addClass('top');
10305 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10310 this.picker().addClass('bottom');
10312 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10315 parseDate : function(value){
10316 if(!value || value instanceof Date){
10319 var v = Date.parseDate(value, this.format);
10320 if (!v && this.useIso) {
10321 v = Date.parseDate(value, 'Y-m-d');
10323 if(!v && this.altFormats){
10324 if(!this.altFormatsArray){
10325 this.altFormatsArray = this.altFormats.split("|");
10327 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
10328 v = Date.parseDate(value, this.altFormatsArray[i]);
10334 formatDate : function(date, fmt){
10335 return (!date || !(date instanceof Date)) ?
10336 date : date.dateFormat(fmt || this.format);
10339 onFocus : function()
10341 Roo.bootstrap.DateField.superclass.onFocus.call(this);
10345 onBlur : function()
10347 Roo.bootstrap.DateField.superclass.onBlur.call(this);
10353 this.picker().show();
10360 if(this.isInline) return;
10361 this.picker().hide();
10362 this.viewMode = this.startViewMode;
10367 onMousedown: function(e){
10368 e.stopPropagation();
10369 e.preventDefault();
10372 keyup: function(e){
10373 Roo.bootstrap.DateField.superclass.keyup.call(this);
10378 fireKey: function(e){
10379 if (!this.picker().isVisible()){
10380 if (e.keyCode == 27) // allow escape to hide and re-show picker
10384 var dateChanged = false,
10386 newDate, newViewDate;
10390 e.preventDefault();
10394 if (!this.keyboardNavigation) break;
10395 dir = e.keyCode == 37 ? -1 : 1;
10398 newDate = this.moveYear(this.date, dir);
10399 newViewDate = this.moveYear(this.viewDate, dir);
10400 } else if (e.shiftKey){
10401 newDate = this.moveMonth(this.date, dir);
10402 newViewDate = this.moveMonth(this.viewDate, dir);
10404 newDate = new Date(this.date);
10405 newDate.setUTCDate(this.date.getUTCDate() + dir);
10406 newViewDate = new Date(this.viewDate);
10407 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
10409 if (this.dateWithinRange(newDate)){
10410 this.date = newDate;
10411 this.viewDate = newViewDate;
10412 this.setValue(this.formatDate(this.date));
10414 e.preventDefault();
10415 dateChanged = true;
10420 if (!this.keyboardNavigation) break;
10421 dir = e.keyCode == 38 ? -1 : 1;
10423 newDate = this.moveYear(this.date, dir);
10424 newViewDate = this.moveYear(this.viewDate, dir);
10425 } else if (e.shiftKey){
10426 newDate = this.moveMonth(this.date, dir);
10427 newViewDate = this.moveMonth(this.viewDate, dir);
10429 newDate = new Date(this.date);
10430 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
10431 newViewDate = new Date(this.viewDate);
10432 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
10434 if (this.dateWithinRange(newDate)){
10435 this.date = newDate;
10436 this.viewDate = newViewDate;
10437 this.setValue(this.formatDate(this.date));
10439 e.preventDefault();
10440 dateChanged = true;
10444 this.setValue(this.formatDate(this.date));
10446 e.preventDefault();
10449 this.setValue(this.formatDate(this.date));
10456 onClick: function(e) {
10457 e.stopPropagation();
10458 e.preventDefault();
10460 var target = e.getTarget();
10462 if(target.nodeName.toLowerCase() === 'i'){
10463 target = Roo.get(target).dom.parentNode;
10466 var nodeName = target.nodeName;
10467 var className = target.className;
10468 var html = target.innerHTML;
10470 switch(nodeName.toLowerCase()) {
10472 switch(className) {
10478 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
10479 switch(this.viewMode){
10481 this.viewDate = this.moveMonth(this.viewDate, dir);
10485 this.viewDate = this.moveYear(this.viewDate, dir);
10491 var date = new Date();
10492 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
10494 this.setValue(this.formatDate(this.date));
10500 if (className.indexOf('disabled') === -1) {
10501 this.viewDate.setUTCDate(1);
10502 if (className.indexOf('month') !== -1) {
10503 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
10505 var year = parseInt(html, 10) || 0;
10506 this.viewDate.setUTCFullYear(year);
10515 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
10516 var day = parseInt(html, 10) || 1;
10517 var year = this.viewDate.getUTCFullYear(),
10518 month = this.viewDate.getUTCMonth();
10520 if (className.indexOf('old') !== -1) {
10527 } else if (className.indexOf('new') !== -1) {
10535 this.date = this.UTCDate(year, month, day,0,0,0,0);
10536 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
10538 this.setValue(this.formatDate(this.date));
10545 setStartDate: function(startDate){
10546 this.startDate = startDate || -Infinity;
10547 if (this.startDate !== -Infinity) {
10548 this.startDate = this.parseDate(this.startDate);
10551 this.updateNavArrows();
10554 setEndDate: function(endDate){
10555 this.endDate = endDate || Infinity;
10556 if (this.endDate !== Infinity) {
10557 this.endDate = this.parseDate(this.endDate);
10560 this.updateNavArrows();
10563 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
10564 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
10565 if (typeof(this.daysOfWeekDisabled) !== 'object') {
10566 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
10568 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
10569 return parseInt(d, 10);
10572 this.updateNavArrows();
10575 updateNavArrows: function() {
10576 var d = new Date(this.viewDate),
10577 year = d.getUTCFullYear(),
10578 month = d.getUTCMonth();
10580 Roo.each(this.picker().select('.prev', true).elements, function(v){
10582 switch (this.viewMode) {
10585 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
10591 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
10598 Roo.each(this.picker().select('.next', true).elements, function(v){
10600 switch (this.viewMode) {
10603 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
10609 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
10617 moveMonth: function(date, dir){
10618 if (!dir) return date;
10619 var new_date = new Date(date.valueOf()),
10620 day = new_date.getUTCDate(),
10621 month = new_date.getUTCMonth(),
10622 mag = Math.abs(dir),
10624 dir = dir > 0 ? 1 : -1;
10627 // If going back one month, make sure month is not current month
10628 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
10630 return new_date.getUTCMonth() == month;
10632 // If going forward one month, make sure month is as expected
10633 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
10635 return new_date.getUTCMonth() != new_month;
10637 new_month = month + dir;
10638 new_date.setUTCMonth(new_month);
10639 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
10640 if (new_month < 0 || new_month > 11)
10641 new_month = (new_month + 12) % 12;
10643 // For magnitudes >1, move one month at a time...
10644 for (var i=0; i<mag; i++)
10645 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
10646 new_date = this.moveMonth(new_date, dir);
10647 // ...then reset the day, keeping it in the new month
10648 new_month = new_date.getUTCMonth();
10649 new_date.setUTCDate(day);
10651 return new_month != new_date.getUTCMonth();
10654 // Common date-resetting loop -- if date is beyond end of month, make it
10657 new_date.setUTCDate(--day);
10658 new_date.setUTCMonth(new_month);
10663 moveYear: function(date, dir){
10664 return this.moveMonth(date, dir*12);
10667 dateWithinRange: function(date){
10668 return date >= this.startDate && date <= this.endDate;
10672 remove: function() {
10673 this.picker().remove();
10678 Roo.apply(Roo.bootstrap.DateField, {
10689 html: '<i class="icon-arrow-left"/>'
10699 html: '<i class="icon-arrow-right"/>'
10741 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
10742 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
10743 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
10744 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
10745 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
10758 navFnc: 'FullYear',
10763 navFnc: 'FullYear',
10768 Roo.apply(Roo.bootstrap.DateField, {
10772 cls: 'datepicker dropdown-menu',
10776 cls: 'datepicker-days',
10780 cls: 'table-condensed',
10782 Roo.bootstrap.DateField.head,
10786 Roo.bootstrap.DateField.footer
10793 cls: 'datepicker-months',
10797 cls: 'table-condensed',
10799 Roo.bootstrap.DateField.head,
10800 Roo.bootstrap.DateField.content,
10801 Roo.bootstrap.DateField.footer
10808 cls: 'datepicker-years',
10812 cls: 'table-condensed',
10814 Roo.bootstrap.DateField.head,
10815 Roo.bootstrap.DateField.content,
10816 Roo.bootstrap.DateField.footer
10835 * @class Roo.bootstrap.CheckBox
10836 * @extends Roo.bootstrap.Input
10837 * Bootstrap CheckBox class
10839 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
10840 * @cfg {String} boxLabel The text that appears beside the checkbox
10841 * @cfg {Boolean} checked initnal the element
10844 * Create a new CheckBox
10845 * @param {Object} config The config object
10848 Roo.bootstrap.CheckBox = function(config){
10849 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
10854 * Fires when the element is checked or unchecked.
10855 * @param {Roo.bootstrap.CheckBox} this This input
10856 * @param {Boolean} checked The new checked value
10862 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
10864 inputType: 'checkbox',
10870 getAutoCreate : function()
10872 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10878 cfg.cls = 'form-group' //input-group
10883 type : this.inputType,
10884 value : (!this.checked) ? this.valueOff : this.value,
10886 placeholder : this.placeholder || ''
10890 if (this.disabled) {
10891 input.disabled=true;
10895 input.checked = this.checked;
10899 input.name = this.name;
10903 input.cls += ' input-' + this.size;
10907 ['xs','sm','md','lg'].map(function(size){
10908 if (settings[size]) {
10909 cfg.cls += ' col-' + size + '-' + settings[size];
10913 var inputblock = input;
10915 if (this.before || this.after) {
10918 cls : 'input-group',
10922 inputblock.cn.push({
10924 cls : 'input-group-addon',
10928 inputblock.cn.push(input);
10930 inputblock.cn.push({
10932 cls : 'input-group-addon',
10939 if (align ==='left' && this.fieldLabel.length) {
10940 Roo.log("left and has label");
10946 cls : 'control-label col-md-' + this.labelWidth,
10947 html : this.fieldLabel
10951 cls : "col-md-" + (12 - this.labelWidth),
10958 } else if ( this.fieldLabel.length) {
10965 cls: 'control-label box-input-label',
10966 //cls : 'input-group-addon',
10967 html : this.fieldLabel
10977 Roo.log(" no label && no align");
10992 html: this.boxLabel
11001 * return the real input element.
11003 inputEl: function ()
11005 return this.el.select('input.form-box',true).first();
11008 initEvents : function()
11010 Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
11012 this.inputEl().on('click', this.onClick, this);
11016 onClick : function()
11018 this.setChecked(!this.checked);
11021 setChecked : function(state,suppressEvent)
11023 this.checked = state;
11025 if(suppressEvent !== true){
11026 this.fireEvent('check', this, state);
11029 this.inputEl().dom.value = state ? this.value : this.valueOff;
11043 * @class Roo.bootstrap.Radio
11044 * @extends Roo.bootstrap.CheckBox
11045 * Bootstrap Radio class
11048 * Create a new Radio
11049 * @param {Object} config The config object
11052 Roo.bootstrap.Radio = function(config){
11053 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
11057 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
11059 inputType: 'radio',
11061 getAutoCreate : function()
11063 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11069 cfg.cls = 'form-group' //input-group
11074 type : this.inputType,
11075 value : (!this.checked) ? this.valueOff : this.value,
11077 placeholder : this.placeholder || ''
11081 if (this.disabled) {
11082 input.disabled=true;
11086 input.checked = this.checked;
11090 input.name = this.name;
11094 input.cls += ' input-' + this.size;
11098 ['xs','sm','md','lg'].map(function(size){
11099 if (settings[size]) {
11100 cfg.cls += ' col-' + size + '-' + settings[size];
11104 var inputblock = input;
11106 if (this.before || this.after) {
11109 cls : 'input-group',
11113 inputblock.cn.push({
11115 cls : 'input-group-addon',
11119 inputblock.cn.push(input);
11121 inputblock.cn.push({
11123 cls : 'input-group-addon',
11130 if (align ==='left' && this.fieldLabel.length) {
11131 Roo.log("left and has label");
11137 cls : 'control-label col-md-' + this.labelWidth,
11138 html : this.fieldLabel
11142 cls : "col-md-" + (12 - this.labelWidth),
11149 } else if ( this.fieldLabel.length) {
11156 cls: 'control-label box-input-label',
11157 //cls : 'input-group-addon',
11158 html : this.fieldLabel
11168 Roo.log(" no label && no align");
11183 html: this.boxLabel
11191 onClick : function()
11193 this.setChecked(true);
11196 setChecked : function(state,suppressEvent)
11198 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
11202 this.checked = state;
11204 if(suppressEvent !== true){
11205 this.fireEvent('check', this, state);
11208 this.inputEl().dom.value = state ? this.value : this.valueOff;
11212 getGroupValue : function()
11214 if(typeof(this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true)) == 'undefined'){
11218 return this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true).value;
11222 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
11223 * @return {Mixed} value The field value
11225 getValue : function(){
11226 return this.getGroupValue();
11240 * @class Roo.bootstrap.HtmlEditor
11241 * @extends Roo.bootstrap.Component
11242 * Bootstrap HtmlEditor class
11245 * Create a new HtmlEditor
11246 * @param {Object} config The config object
11249 Roo.bootstrap.HtmlEditor = function(config){
11250 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
11255 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.Component, {
11257 getAutoCreate : function()
11261 // var toolbar = new Roo.bootstrap.ButtonGroup({
11265 // new Roo.bootstrap.Button({
11278 * @class Roo.bootstrap.Table.AbstractSelectionModel
11279 * @extends Roo.util.Observable
11280 * Abstract base class for grid SelectionModels. It provides the interface that should be
11281 * implemented by descendant classes. This class should not be directly instantiated.
11284 Roo.bootstrap.Table.AbstractSelectionModel = function(){
11285 this.locked = false;
11286 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
11290 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
11291 /** @ignore Called by the grid automatically. Do not call directly. */
11292 init : function(grid){
11298 * Locks the selections.
11301 this.locked = true;
11305 * Unlocks the selections.
11307 unlock : function(){
11308 this.locked = false;
11312 * Returns true if the selections are locked.
11313 * @return {Boolean}
11315 isLocked : function(){
11316 return this.locked;
11320 * @class Roo.bootstrap.Table.ColumnModel
11321 * @extends Roo.util.Observable
11322 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
11323 * the columns in the table.
11326 * @param {Object} config An Array of column config objects. See this class's
11327 * config objects for details.
11329 Roo.bootstrap.Table.ColumnModel = function(config){
11331 * The config passed into the constructor
11333 this.config = config;
11336 // if no id, create one
11337 // if the column does not have a dataIndex mapping,
11338 // map it to the order it is in the config
11339 for(var i = 0, len = config.length; i < len; i++){
11341 if(typeof c.dataIndex == "undefined"){
11344 if(typeof c.renderer == "string"){
11345 c.renderer = Roo.util.Format[c.renderer];
11347 if(typeof c.id == "undefined"){
11350 // if(c.editor && c.editor.xtype){
11351 // c.editor = Roo.factory(c.editor, Roo.grid);
11353 // if(c.editor && c.editor.isFormField){
11354 // c.editor = new Roo.grid.GridEditor(c.editor);
11357 this.lookup[c.id] = c;
11361 * The width of columns which have no width specified (defaults to 100)
11364 this.defaultWidth = 100;
11367 * Default sortable of columns which have no sortable specified (defaults to false)
11370 this.defaultSortable = false;
11374 * @event widthchange
11375 * Fires when the width of a column changes.
11376 * @param {ColumnModel} this
11377 * @param {Number} columnIndex The column index
11378 * @param {Number} newWidth The new width
11380 "widthchange": true,
11382 * @event headerchange
11383 * Fires when the text of a header changes.
11384 * @param {ColumnModel} this
11385 * @param {Number} columnIndex The column index
11386 * @param {Number} newText The new header text
11388 "headerchange": true,
11390 * @event hiddenchange
11391 * Fires when a column is hidden or "unhidden".
11392 * @param {ColumnModel} this
11393 * @param {Number} columnIndex The column index
11394 * @param {Boolean} hidden true if hidden, false otherwise
11396 "hiddenchange": true,
11398 * @event columnmoved
11399 * Fires when a column is moved.
11400 * @param {ColumnModel} this
11401 * @param {Number} oldIndex
11402 * @param {Number} newIndex
11404 "columnmoved" : true,
11406 * @event columlockchange
11407 * Fires when a column's locked state is changed
11408 * @param {ColumnModel} this
11409 * @param {Number} colIndex
11410 * @param {Boolean} locked true if locked
11412 "columnlockchange" : true
11414 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
11416 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
11418 * @cfg {String} header The header text to display in the Grid view.
11421 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
11422 * {@link Roo.data.Record} definition from which to draw the column's value. If not
11423 * specified, the column's index is used as an index into the Record's data Array.
11426 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
11427 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
11430 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
11431 * Defaults to the value of the {@link #defaultSortable} property.
11432 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
11435 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
11438 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
11441 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
11444 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
11447 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
11448 * given the cell's data value. See {@link #setRenderer}. If not specified, the
11449 * default renderer uses the raw data value.
11452 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
11456 * Returns the id of the column at the specified index.
11457 * @param {Number} index The column index
11458 * @return {String} the id
11460 getColumnId : function(index){
11461 return this.config[index].id;
11465 * Returns the column for a specified id.
11466 * @param {String} id The column id
11467 * @return {Object} the column
11469 getColumnById : function(id){
11470 return this.lookup[id];
11475 * Returns the column for a specified dataIndex.
11476 * @param {String} dataIndex The column dataIndex
11477 * @return {Object|Boolean} the column or false if not found
11479 getColumnByDataIndex: function(dataIndex){
11480 var index = this.findColumnIndex(dataIndex);
11481 return index > -1 ? this.config[index] : false;
11485 * Returns the index for a specified column id.
11486 * @param {String} id The column id
11487 * @return {Number} the index, or -1 if not found
11489 getIndexById : function(id){
11490 for(var i = 0, len = this.config.length; i < len; i++){
11491 if(this.config[i].id == id){
11499 * Returns the index for a specified column dataIndex.
11500 * @param {String} dataIndex The column dataIndex
11501 * @return {Number} the index, or -1 if not found
11504 findColumnIndex : function(dataIndex){
11505 for(var i = 0, len = this.config.length; i < len; i++){
11506 if(this.config[i].dataIndex == dataIndex){
11514 moveColumn : function(oldIndex, newIndex){
11515 var c = this.config[oldIndex];
11516 this.config.splice(oldIndex, 1);
11517 this.config.splice(newIndex, 0, c);
11518 this.dataMap = null;
11519 this.fireEvent("columnmoved", this, oldIndex, newIndex);
11522 isLocked : function(colIndex){
11523 return this.config[colIndex].locked === true;
11526 setLocked : function(colIndex, value, suppressEvent){
11527 if(this.isLocked(colIndex) == value){
11530 this.config[colIndex].locked = value;
11531 if(!suppressEvent){
11532 this.fireEvent("columnlockchange", this, colIndex, value);
11536 getTotalLockedWidth : function(){
11537 var totalWidth = 0;
11538 for(var i = 0; i < this.config.length; i++){
11539 if(this.isLocked(i) && !this.isHidden(i)){
11540 this.totalWidth += this.getColumnWidth(i);
11546 getLockedCount : function(){
11547 for(var i = 0, len = this.config.length; i < len; i++){
11548 if(!this.isLocked(i)){
11555 * Returns the number of columns.
11558 getColumnCount : function(visibleOnly){
11559 if(visibleOnly === true){
11561 for(var i = 0, len = this.config.length; i < len; i++){
11562 if(!this.isHidden(i)){
11568 return this.config.length;
11572 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
11573 * @param {Function} fn
11574 * @param {Object} scope (optional)
11575 * @return {Array} result
11577 getColumnsBy : function(fn, scope){
11579 for(var i = 0, len = this.config.length; i < len; i++){
11580 var c = this.config[i];
11581 if(fn.call(scope||this, c, i) === true){
11589 * Returns true if the specified column is sortable.
11590 * @param {Number} col The column index
11591 * @return {Boolean}
11593 isSortable : function(col){
11594 if(typeof this.config[col].sortable == "undefined"){
11595 return this.defaultSortable;
11597 return this.config[col].sortable;
11601 * Returns the rendering (formatting) function defined for the column.
11602 * @param {Number} col The column index.
11603 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
11605 getRenderer : function(col){
11606 if(!this.config[col].renderer){
11607 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
11609 return this.config[col].renderer;
11613 * Sets the rendering (formatting) function for a column.
11614 * @param {Number} col The column index
11615 * @param {Function} fn The function to use to process the cell's raw data
11616 * to return HTML markup for the grid view. The render function is called with
11617 * the following parameters:<ul>
11618 * <li>Data value.</li>
11619 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
11620 * <li>css A CSS style string to apply to the table cell.</li>
11621 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
11622 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
11623 * <li>Row index</li>
11624 * <li>Column index</li>
11625 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
11627 setRenderer : function(col, fn){
11628 this.config[col].renderer = fn;
11632 * Returns the width for the specified column.
11633 * @param {Number} col The column index
11636 getColumnWidth : function(col){
11637 return this.config[col].width * 1 || this.defaultWidth;
11641 * Sets the width for a column.
11642 * @param {Number} col The column index
11643 * @param {Number} width The new width
11645 setColumnWidth : function(col, width, suppressEvent){
11646 this.config[col].width = width;
11647 this.totalWidth = null;
11648 if(!suppressEvent){
11649 this.fireEvent("widthchange", this, col, width);
11654 * Returns the total width of all columns.
11655 * @param {Boolean} includeHidden True to include hidden column widths
11658 getTotalWidth : function(includeHidden){
11659 if(!this.totalWidth){
11660 this.totalWidth = 0;
11661 for(var i = 0, len = this.config.length; i < len; i++){
11662 if(includeHidden || !this.isHidden(i)){
11663 this.totalWidth += this.getColumnWidth(i);
11667 return this.totalWidth;
11671 * Returns the header for the specified column.
11672 * @param {Number} col The column index
11675 getColumnHeader : function(col){
11676 return this.config[col].header;
11680 * Sets the header for a column.
11681 * @param {Number} col The column index
11682 * @param {String} header The new header
11684 setColumnHeader : function(col, header){
11685 this.config[col].header = header;
11686 this.fireEvent("headerchange", this, col, header);
11690 * Returns the tooltip for the specified column.
11691 * @param {Number} col The column index
11694 getColumnTooltip : function(col){
11695 return this.config[col].tooltip;
11698 * Sets the tooltip for a column.
11699 * @param {Number} col The column index
11700 * @param {String} tooltip The new tooltip
11702 setColumnTooltip : function(col, tooltip){
11703 this.config[col].tooltip = tooltip;
11707 * Returns the dataIndex for the specified column.
11708 * @param {Number} col The column index
11711 getDataIndex : function(col){
11712 return this.config[col].dataIndex;
11716 * Sets the dataIndex for a column.
11717 * @param {Number} col The column index
11718 * @param {Number} dataIndex The new dataIndex
11720 setDataIndex : function(col, dataIndex){
11721 this.config[col].dataIndex = dataIndex;
11727 * Returns true if the cell is editable.
11728 * @param {Number} colIndex The column index
11729 * @param {Number} rowIndex The row index
11730 * @return {Boolean}
11732 isCellEditable : function(colIndex, rowIndex){
11733 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
11737 * Returns the editor defined for the cell/column.
11738 * return false or null to disable editing.
11739 * @param {Number} colIndex The column index
11740 * @param {Number} rowIndex The row index
11743 getCellEditor : function(colIndex, rowIndex){
11744 return this.config[colIndex].editor;
11748 * Sets if a column is editable.
11749 * @param {Number} col The column index
11750 * @param {Boolean} editable True if the column is editable
11752 setEditable : function(col, editable){
11753 this.config[col].editable = editable;
11758 * Returns true if the column is hidden.
11759 * @param {Number} colIndex The column index
11760 * @return {Boolean}
11762 isHidden : function(colIndex){
11763 return this.config[colIndex].hidden;
11768 * Returns true if the column width cannot be changed
11770 isFixed : function(colIndex){
11771 return this.config[colIndex].fixed;
11775 * Returns true if the column can be resized
11776 * @return {Boolean}
11778 isResizable : function(colIndex){
11779 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
11782 * Sets if a column is hidden.
11783 * @param {Number} colIndex The column index
11784 * @param {Boolean} hidden True if the column is hidden
11786 setHidden : function(colIndex, hidden){
11787 this.config[colIndex].hidden = hidden;
11788 this.totalWidth = null;
11789 this.fireEvent("hiddenchange", this, colIndex, hidden);
11793 * Sets the editor for a column.
11794 * @param {Number} col The column index
11795 * @param {Object} editor The editor object
11797 setEditor : function(col, editor){
11798 this.config[col].editor = editor;
11802 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
11803 if(typeof value == "string" && value.length < 1){
11809 // Alias for backwards compatibility
11810 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
11813 * @extends Roo.bootstrap.Table.AbstractSelectionModel
11814 * @class Roo.bootstrap.Table.RowSelectionModel
11815 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
11816 * It supports multiple selections and keyboard selection/navigation.
11818 * @param {Object} config
11821 Roo.bootstrap.Table.RowSelectionModel = function(config){
11822 Roo.apply(this, config);
11823 this.selections = new Roo.util.MixedCollection(false, function(o){
11828 this.lastActive = false;
11832 * @event selectionchange
11833 * Fires when the selection changes
11834 * @param {SelectionModel} this
11836 "selectionchange" : true,
11838 * @event afterselectionchange
11839 * Fires after the selection changes (eg. by key press or clicking)
11840 * @param {SelectionModel} this
11842 "afterselectionchange" : true,
11844 * @event beforerowselect
11845 * Fires when a row is selected being selected, return false to cancel.
11846 * @param {SelectionModel} this
11847 * @param {Number} rowIndex The selected index
11848 * @param {Boolean} keepExisting False if other selections will be cleared
11850 "beforerowselect" : true,
11853 * Fires when a row is selected.
11854 * @param {SelectionModel} this
11855 * @param {Number} rowIndex The selected index
11856 * @param {Roo.data.Record} r The record
11858 "rowselect" : true,
11860 * @event rowdeselect
11861 * Fires when a row is deselected.
11862 * @param {SelectionModel} this
11863 * @param {Number} rowIndex The selected index
11865 "rowdeselect" : true
11867 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
11868 this.locked = false;
11871 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
11873 * @cfg {Boolean} singleSelect
11874 * True to allow selection of only one row at a time (defaults to false)
11876 singleSelect : false,
11879 initEvents : function(){
11881 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
11882 this.grid.on("mousedown", this.handleMouseDown, this);
11883 }else{ // allow click to work like normal
11884 this.grid.on("rowclick", this.handleDragableRowClick, this);
11887 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
11888 "up" : function(e){
11890 this.selectPrevious(e.shiftKey);
11891 }else if(this.last !== false && this.lastActive !== false){
11892 var last = this.last;
11893 this.selectRange(this.last, this.lastActive-1);
11894 this.grid.getView().focusRow(this.lastActive);
11895 if(last !== false){
11899 this.selectFirstRow();
11901 this.fireEvent("afterselectionchange", this);
11903 "down" : function(e){
11905 this.selectNext(e.shiftKey);
11906 }else if(this.last !== false && this.lastActive !== false){
11907 var last = this.last;
11908 this.selectRange(this.last, this.lastActive+1);
11909 this.grid.getView().focusRow(this.lastActive);
11910 if(last !== false){
11914 this.selectFirstRow();
11916 this.fireEvent("afterselectionchange", this);
11921 var view = this.grid.view;
11922 view.on("refresh", this.onRefresh, this);
11923 view.on("rowupdated", this.onRowUpdated, this);
11924 view.on("rowremoved", this.onRemove, this);
11928 onRefresh : function(){
11929 var ds = this.grid.dataSource, i, v = this.grid.view;
11930 var s = this.selections;
11931 s.each(function(r){
11932 if((i = ds.indexOfId(r.id)) != -1){
11941 onRemove : function(v, index, r){
11942 this.selections.remove(r);
11946 onRowUpdated : function(v, index, r){
11947 if(this.isSelected(r)){
11948 v.onRowSelect(index);
11954 * @param {Array} records The records to select
11955 * @param {Boolean} keepExisting (optional) True to keep existing selections
11957 selectRecords : function(records, keepExisting){
11959 this.clearSelections();
11961 var ds = this.grid.dataSource;
11962 for(var i = 0, len = records.length; i < len; i++){
11963 this.selectRow(ds.indexOf(records[i]), true);
11968 * Gets the number of selected rows.
11971 getCount : function(){
11972 return this.selections.length;
11976 * Selects the first row in the grid.
11978 selectFirstRow : function(){
11983 * Select the last row.
11984 * @param {Boolean} keepExisting (optional) True to keep existing selections
11986 selectLastRow : function(keepExisting){
11987 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
11991 * Selects the row immediately following the last selected row.
11992 * @param {Boolean} keepExisting (optional) True to keep existing selections
11994 selectNext : function(keepExisting){
11995 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
11996 this.selectRow(this.last+1, keepExisting);
11997 this.grid.getView().focusRow(this.last);
12002 * Selects the row that precedes the last selected row.
12003 * @param {Boolean} keepExisting (optional) True to keep existing selections
12005 selectPrevious : function(keepExisting){
12007 this.selectRow(this.last-1, keepExisting);
12008 this.grid.getView().focusRow(this.last);
12013 * Returns the selected records
12014 * @return {Array} Array of selected records
12016 getSelections : function(){
12017 return [].concat(this.selections.items);
12021 * Returns the first selected record.
12024 getSelected : function(){
12025 return this.selections.itemAt(0);
12030 * Clears all selections.
12032 clearSelections : function(fast){
12033 if(this.locked) return;
12035 var ds = this.grid.dataSource;
12036 var s = this.selections;
12037 s.each(function(r){
12038 this.deselectRow(ds.indexOfId(r.id));
12042 this.selections.clear();
12049 * Selects all rows.
12051 selectAll : function(){
12052 if(this.locked) return;
12053 this.selections.clear();
12054 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
12055 this.selectRow(i, true);
12060 * Returns True if there is a selection.
12061 * @return {Boolean}
12063 hasSelection : function(){
12064 return this.selections.length > 0;
12068 * Returns True if the specified row is selected.
12069 * @param {Number/Record} record The record or index of the record to check
12070 * @return {Boolean}
12072 isSelected : function(index){
12073 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
12074 return (r && this.selections.key(r.id) ? true : false);
12078 * Returns True if the specified record id is selected.
12079 * @param {String} id The id of record to check
12080 * @return {Boolean}
12082 isIdSelected : function(id){
12083 return (this.selections.key(id) ? true : false);
12087 handleMouseDown : function(e, t){
12088 var view = this.grid.getView(), rowIndex;
12089 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
12092 if(e.shiftKey && this.last !== false){
12093 var last = this.last;
12094 this.selectRange(last, rowIndex, e.ctrlKey);
12095 this.last = last; // reset the last
12096 view.focusRow(rowIndex);
12098 var isSelected = this.isSelected(rowIndex);
12099 if(e.button !== 0 && isSelected){
12100 view.focusRow(rowIndex);
12101 }else if(e.ctrlKey && isSelected){
12102 this.deselectRow(rowIndex);
12103 }else if(!isSelected){
12104 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
12105 view.focusRow(rowIndex);
12108 this.fireEvent("afterselectionchange", this);
12111 handleDragableRowClick : function(grid, rowIndex, e)
12113 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
12114 this.selectRow(rowIndex, false);
12115 grid.view.focusRow(rowIndex);
12116 this.fireEvent("afterselectionchange", this);
12121 * Selects multiple rows.
12122 * @param {Array} rows Array of the indexes of the row to select
12123 * @param {Boolean} keepExisting (optional) True to keep existing selections
12125 selectRows : function(rows, keepExisting){
12127 this.clearSelections();
12129 for(var i = 0, len = rows.length; i < len; i++){
12130 this.selectRow(rows[i], true);
12135 * Selects a range of rows. All rows in between startRow and endRow are also selected.
12136 * @param {Number} startRow The index of the first row in the range
12137 * @param {Number} endRow The index of the last row in the range
12138 * @param {Boolean} keepExisting (optional) True to retain existing selections
12140 selectRange : function(startRow, endRow, keepExisting){
12141 if(this.locked) return;
12143 this.clearSelections();
12145 if(startRow <= endRow){
12146 for(var i = startRow; i <= endRow; i++){
12147 this.selectRow(i, true);
12150 for(var i = startRow; i >= endRow; i--){
12151 this.selectRow(i, true);
12157 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
12158 * @param {Number} startRow The index of the first row in the range
12159 * @param {Number} endRow The index of the last row in the range
12161 deselectRange : function(startRow, endRow, preventViewNotify){
12162 if(this.locked) return;
12163 for(var i = startRow; i <= endRow; i++){
12164 this.deselectRow(i, preventViewNotify);
12170 * @param {Number} row The index of the row to select
12171 * @param {Boolean} keepExisting (optional) True to keep existing selections
12173 selectRow : function(index, keepExisting, preventViewNotify){
12174 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
12175 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
12176 if(!keepExisting || this.singleSelect){
12177 this.clearSelections();
12179 var r = this.grid.dataSource.getAt(index);
12180 this.selections.add(r);
12181 this.last = this.lastActive = index;
12182 if(!preventViewNotify){
12183 this.grid.getView().onRowSelect(index);
12185 this.fireEvent("rowselect", this, index, r);
12186 this.fireEvent("selectionchange", this);
12192 * @param {Number} row The index of the row to deselect
12194 deselectRow : function(index, preventViewNotify){
12195 if(this.locked) return;
12196 if(this.last == index){
12199 if(this.lastActive == index){
12200 this.lastActive = false;
12202 var r = this.grid.dataSource.getAt(index);
12203 this.selections.remove(r);
12204 if(!preventViewNotify){
12205 this.grid.getView().onRowDeselect(index);
12207 this.fireEvent("rowdeselect", this, index);
12208 this.fireEvent("selectionchange", this);
12212 restoreLast : function(){
12214 this.last = this._last;
12219 acceptsNav : function(row, col, cm){
12220 return !cm.isHidden(col) && cm.isCellEditable(col, row);
12224 onEditorKey : function(field, e){
12225 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
12230 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
12232 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
12234 }else if(k == e.ENTER && !e.ctrlKey){
12238 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
12240 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
12242 }else if(k == e.ESC){
12246 g.startEditing(newCell[0], newCell[1]);