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';
2910 if(o.clientValidation === false || this.form.isValid()){
2912 if (this.form.progressUrl) {
2913 this.form.findField('UPLOAD_IDENTIFIER').setValue(
2914 (new Date() * 1) + '' + Math.random());
2919 Roo.Ajax.request(Roo.apply(this.createCallback(), {
2920 form:this.form.el.dom,
2921 url:this.getUrl(!isPost),
2923 params:isPost ? this.getParams() : null,
2924 isUpload: this.form.fileUpload
2927 this.uploadProgress();
2929 }else if (o.clientValidation !== false){ // client validation failed
2930 this.failureType = Roo.form.Action.CLIENT_INVALID;
2931 this.form.afterAction(this, false);
2935 success : function(response)
2937 this.uploadComplete= true;
2938 if (this.haveProgress) {
2939 Roo.MessageBox.hide();
2943 var result = this.processResponse(response);
2944 if(result === true || result.success){
2945 this.form.afterAction(this, true);
2949 this.form.markInvalid(result.errors);
2950 this.failureType = Roo.form.Action.SERVER_INVALID;
2952 this.form.afterAction(this, false);
2954 failure : function(response)
2956 this.uploadComplete= true;
2957 if (this.haveProgress) {
2958 Roo.MessageBox.hide();
2961 this.response = response;
2962 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2963 this.form.afterAction(this, false);
2966 handleResponse : function(response){
2967 if(this.form.errorReader){
2968 var rs = this.form.errorReader.read(response);
2971 for(var i = 0, len = rs.records.length; i < len; i++) {
2972 var r = rs.records[i];
2976 if(errors.length < 1){
2980 success : rs.success,
2986 ret = Roo.decode(response.responseText);
2990 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
3000 Roo.form.Action.Load = function(form, options){
3001 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
3002 this.reader = this.form.reader;
3005 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
3010 Roo.Ajax.request(Roo.apply(
3011 this.createCallback(), {
3012 method:this.getMethod(),
3013 url:this.getUrl(false),
3014 params:this.getParams()
3018 success : function(response){
3020 var result = this.processResponse(response);
3021 if(result === true || !result.success || !result.data){
3022 this.failureType = Roo.form.Action.LOAD_FAILURE;
3023 this.form.afterAction(this, false);
3026 this.form.clearInvalid();
3027 this.form.setValues(result.data);
3028 this.form.afterAction(this, true);
3031 handleResponse : function(response){
3032 if(this.form.reader){
3033 var rs = this.form.reader.read(response);
3034 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
3036 success : rs.success,
3040 return Roo.decode(response.responseText);
3044 Roo.form.Action.ACTION_TYPES = {
3045 'load' : Roo.form.Action.Load,
3046 'submit' : Roo.form.Action.Submit
3055 * @class Roo.bootstrap.Form
3056 * @extends Roo.bootstrap.Component
3057 * Bootstrap Form class
3058 * @cfg {String} method GET | POST (default POST)
3059 * @cfg {String} labelAlign top | left (default top)
3060 * @cfg {String} align left | right - for navbars
3065 * @param {Object} config The config object
3069 Roo.bootstrap.Form = function(config){
3070 Roo.bootstrap.Form.superclass.constructor.call(this, config);
3073 * @event clientvalidation
3074 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
3075 * @param {Form} this
3076 * @param {Boolean} valid true if the form has passed client-side validation
3078 clientvalidation: true,
3080 * @event beforeaction
3081 * Fires before any action is performed. Return false to cancel the action.
3082 * @param {Form} this
3083 * @param {Action} action The action to be performed
3087 * @event actionfailed
3088 * Fires when an action fails.
3089 * @param {Form} this
3090 * @param {Action} action The action that failed
3092 actionfailed : true,
3094 * @event actioncomplete
3095 * Fires when an action is completed.
3096 * @param {Form} this
3097 * @param {Action} action The action that completed
3099 actioncomplete : true
3104 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
3107 * @cfg {String} method
3108 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
3113 * The URL to use for form actions if one isn't supplied in the action options.
3116 * @cfg {Boolean} fileUpload
3117 * Set to true if this form is a file upload.
3121 * @cfg {Object} baseParams
3122 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
3126 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
3130 * @cfg {Sting} align (left|right) for navbar forms
3135 activeAction : null,
3138 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3139 * element by passing it or its id or mask the form itself by passing in true.
3142 waitMsgTarget : false,
3147 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3148 * element by passing it or its id or mask the form itself by passing in true.
3152 getAutoCreate : function(){
3156 method : this.method || 'POST',
3157 id : this.id || Roo.id(),
3160 if (this.parent().xtype.match(/^Nav/)) {
3161 cfg.cls = 'navbar-form navbar-' + this.align;
3165 if (this.labelAlign == 'left' ) {
3166 cfg.cls += ' form-horizontal';
3172 initEvents : function()
3174 this.el.on('submit', this.onSubmit, this);
3179 onSubmit : function(e){
3184 * Returns true if client-side validation on the form is successful.
3187 isValid : function(){
3188 var items = this.getItems();
3190 items.each(function(f){
3199 * Returns true if any fields in this form have changed since their original load.
3202 isDirty : function(){
3204 var items = this.getItems();
3205 items.each(function(f){
3215 * Performs a predefined action (submit or load) or custom actions you define on this form.
3216 * @param {String} actionName The name of the action type
3217 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
3218 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
3219 * accept other config options):
3221 Property Type Description
3222 ---------------- --------------- ----------------------------------------------------------------------------------
3223 url String The url for the action (defaults to the form's url)
3224 method String The form method to use (defaults to the form's method, or POST if not defined)
3225 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
3226 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
3227 validate the form on the client (defaults to false)
3229 * @return {BasicForm} this
3231 doAction : function(action, options){
3232 if(typeof action == 'string'){
3233 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
3236 if(this.fireEvent('beforeaction', this, action) !== false){
3237 this.beforeAction(action);
3238 action.run.defer(100, action);
3244 beforeAction : function(action){
3245 var o = action.options;
3247 // not really supported yet.. ??
3249 //if(this.waitMsgTarget === true){
3250 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
3251 //}else if(this.waitMsgTarget){
3252 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
3253 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
3255 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
3261 afterAction : function(action, success){
3262 this.activeAction = null;
3263 var o = action.options;
3265 //if(this.waitMsgTarget === true){
3267 //}else if(this.waitMsgTarget){
3268 // this.waitMsgTarget.unmask();
3270 // Roo.MessageBox.updateProgress(1);
3271 // Roo.MessageBox.hide();
3278 Roo.callback(o.success, o.scope, [this, action]);
3279 this.fireEvent('actioncomplete', this, action);
3283 // failure condition..
3284 // we have a scenario where updates need confirming.
3285 // eg. if a locking scenario exists..
3286 // we look for { errors : { needs_confirm : true }} in the response.
3288 (typeof(action.result) != 'undefined') &&
3289 (typeof(action.result.errors) != 'undefined') &&
3290 (typeof(action.result.errors.needs_confirm) != 'undefined')
3293 Roo.log("not supported yet");
3296 Roo.MessageBox.confirm(
3297 "Change requires confirmation",
3298 action.result.errorMsg,
3303 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
3313 Roo.callback(o.failure, o.scope, [this, action]);
3314 // show an error message if no failed handler is set..
3315 if (!this.hasListener('actionfailed')) {
3316 Roo.log("need to add dialog support");
3318 Roo.MessageBox.alert("Error",
3319 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
3320 action.result.errorMsg :
3321 "Saving Failed, please check your entries or try again"
3326 this.fireEvent('actionfailed', this, action);
3331 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
3332 * @param {String} id The value to search for
3335 findField : function(id){
3336 var items = this.getItems();
3337 var field = items.get(id);
3339 items.each(function(f){
3340 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
3347 return field || null;
3350 * Mark fields in this form invalid in bulk.
3351 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
3352 * @return {BasicForm} this
3354 markInvalid : function(errors){
3355 if(errors instanceof Array){
3356 for(var i = 0, len = errors.length; i < len; i++){
3357 var fieldError = errors[i];
3358 var f = this.findField(fieldError.id);
3360 f.markInvalid(fieldError.msg);
3366 if(typeof errors[id] != 'function' && (field = this.findField(id))){
3367 field.markInvalid(errors[id]);
3371 //Roo.each(this.childForms || [], function (f) {
3372 // f.markInvalid(errors);
3379 * Set values for fields in this form in bulk.
3380 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
3381 * @return {BasicForm} this
3383 setValues : function(values){
3384 if(values instanceof Array){ // array of objects
3385 for(var i = 0, len = values.length; i < len; i++){
3387 var f = this.findField(v.id);
3389 f.setValue(v.value);
3390 if(this.trackResetOnLoad){
3391 f.originalValue = f.getValue();
3395 }else{ // object hash
3398 if(typeof values[id] != 'function' && (field = this.findField(id))){
3400 if (field.setFromData &&
3402 field.displayField &&
3403 // combos' with local stores can
3404 // be queried via setValue()
3405 // to set their value..
3406 (field.store && !field.store.isLocal)
3410 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
3411 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
3412 field.setFromData(sd);
3415 field.setValue(values[id]);
3419 if(this.trackResetOnLoad){
3420 field.originalValue = field.getValue();
3426 //Roo.each(this.childForms || [], function (f) {
3427 // f.setValues(values);
3434 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
3435 * they are returned as an array.
3436 * @param {Boolean} asString
3439 getValues : function(asString){
3440 //if (this.childForms) {
3441 // copy values from the child forms
3442 // Roo.each(this.childForms, function (f) {
3443 // this.setValues(f.getValues());
3449 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
3450 if(asString === true){
3453 return Roo.urlDecode(fs);
3457 * Returns the fields in this form as an object with key/value pairs.
3458 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
3461 getFieldValues : function(with_hidden)
3463 var items = this.getItems();
3465 items.each(function(f){
3469 var v = f.getValue();
3470 if (f.inputType =='radio') {
3471 if (typeof(ret[f.getName()]) == 'undefined') {
3472 ret[f.getName()] = ''; // empty..
3475 if (!f.el.dom.checked) {
3483 // not sure if this supported any more..
3484 if ((typeof(v) == 'object') && f.getRawValue) {
3485 v = f.getRawValue() ; // dates..
3487 // combo boxes where name != hiddenName...
3488 if (f.name != f.getName()) {
3489 ret[f.name] = f.getRawValue();
3491 ret[f.getName()] = v;
3498 * Clears all invalid messages in this form.
3499 * @return {BasicForm} this
3501 clearInvalid : function(){
3502 var items = this.getItems();
3504 items.each(function(f){
3515 * @return {BasicForm} this
3518 var items = this.getItems();
3519 items.each(function(f){
3523 Roo.each(this.childForms || [], function (f) {
3530 getItems : function()
3532 var r=new Roo.util.MixedCollection(false, function(o){
3533 return o.id || (o.id = Roo.id());
3535 var iter = function(el) {
3542 Roo.each(el.items,function(e) {
3561 * Ext JS Library 1.1.1
3562 * Copyright(c) 2006-2007, Ext JS, LLC.
3564 * Originally Released Under LGPL - original licence link has changed is not relivant.
3567 * <script type="text/javascript">
3570 * @class Roo.form.VTypes
3571 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
3574 Roo.form.VTypes = function(){
3575 // closure these in so they are only created once.
3576 var alpha = /^[a-zA-Z_]+$/;
3577 var alphanum = /^[a-zA-Z0-9_]+$/;
3578 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
3579 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
3581 // All these messages and functions are configurable
3584 * The function used to validate email addresses
3585 * @param {String} value The email address
3587 'email' : function(v){
3588 return email.test(v);
3591 * The error text to display when the email validation function returns false
3594 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
3596 * The keystroke filter mask to be applied on email input
3599 'emailMask' : /[a-z0-9_\.\-@]/i,
3602 * The function used to validate URLs
3603 * @param {String} value The URL
3605 'url' : function(v){
3609 * The error text to display when the url validation function returns false
3612 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
3615 * The function used to validate alpha values
3616 * @param {String} value The value
3618 'alpha' : function(v){
3619 return alpha.test(v);
3622 * The error text to display when the alpha validation function returns false
3625 'alphaText' : 'This field should only contain letters and _',
3627 * The keystroke filter mask to be applied on alpha input
3630 'alphaMask' : /[a-z_]/i,
3633 * The function used to validate alphanumeric values
3634 * @param {String} value The value
3636 'alphanum' : function(v){
3637 return alphanum.test(v);
3640 * The error text to display when the alphanumeric validation function returns false
3643 'alphanumText' : 'This field should only contain letters, numbers and _',
3645 * The keystroke filter mask to be applied on alphanumeric input
3648 'alphanumMask' : /[a-z0-9_]/i
3658 * @class Roo.bootstrap.Input
3659 * @extends Roo.bootstrap.Component
3660 * Bootstrap Input class
3661 * @cfg {Boolean} disabled is it disabled
3662 * @cfg {String} fieldLabel - the label associated
3663 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3664 * @cfg {String} name name of the input
3665 * @cfg {string} fieldLabel - the label associated
3666 * @cfg {string} inputType - input / file submit ...
3667 * @cfg {string} placeholder - placeholder to put in text.
3668 * @cfg {string} before - input group add on before
3669 * @cfg {string} after - input group add on after
3670 * @cfg {string} size - (lg|sm) or leave empty..
3671 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3672 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3673 * @cfg {Number} md colspan out of 12 for computer-sized screens
3674 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3675 * @cfg {string} value default value of the input
3676 * @cfg {Number} labelWidth set the width of label (0-12)
3677 * @cfg {String} labelAlign (top|left)
3681 * Create a new Input
3682 * @param {Object} config The config object
3685 Roo.bootstrap.Input = function(config){
3686 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3691 * Fires when this field receives input focus.
3692 * @param {Roo.form.Field} this
3697 * Fires when this field loses input focus.
3698 * @param {Roo.form.Field} this
3703 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3704 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3705 * @param {Roo.form.Field} this
3706 * @param {Roo.EventObject} e The event object
3711 * Fires just before the field blurs if the field value has changed.
3712 * @param {Roo.form.Field} this
3713 * @param {Mixed} newValue The new value
3714 * @param {Mixed} oldValue The original value
3719 * Fires after the field has been marked as invalid.
3720 * @param {Roo.form.Field} this
3721 * @param {String} msg The validation message
3726 * Fires after the field has been validated with no errors.
3727 * @param {Roo.form.Field} this
3732 * Fires after the key up
3733 * @param {Roo.form.Field} this
3734 * @param {Roo.EventObject} e The event Object
3740 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3742 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3743 automatic validation (defaults to "keyup").
3745 validationEvent : "keyup",
3747 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3749 validateOnBlur : true,
3751 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3753 validationDelay : 250,
3755 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3757 focusClass : "x-form-focus", // not needed???
3761 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3763 invalidClass : "has-error",
3766 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3768 selectOnFocus : false,
3771 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3775 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3780 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3782 disableKeyFilter : false,
3785 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3789 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3793 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3795 blankText : "This field is required",
3798 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3802 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3804 maxLength : Number.MAX_VALUE,
3806 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3808 minLengthText : "The minimum length for this field is {0}",
3810 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3812 maxLengthText : "The maximum length for this field is {0}",
3816 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3817 * If available, this function will be called only after the basic validators all return true, and will be passed the
3818 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3822 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3823 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3824 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
3828 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3850 parentLabelAlign : function()
3853 while (parent.parent()) {
3854 parent = parent.parent();
3855 if (typeof(parent.labelAlign) !='undefined') {
3856 return parent.labelAlign;
3863 getAutoCreate : function(){
3865 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
3871 if(this.inputType != 'hidden'){
3872 cfg.cls = 'form-group' //input-group
3878 type : this.inputType,
3880 cls : 'form-control',
3881 placeholder : this.placeholder || ''
3885 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
3886 input.maxLength = this.maxLength;
3889 if (this.disabled) {
3890 input.disabled=true;
3894 input.name = this.name;
3897 input.cls += ' input-' + this.size;
3900 ['xs','sm','md','lg'].map(function(size){
3901 if (settings[size]) {
3902 cfg.cls += ' col-' + size + '-' + settings[size];
3906 var inputblock = input;
3908 if (this.before || this.after) {
3911 cls : 'input-group',
3915 inputblock.cn.push({
3917 cls : 'input-group-addon',
3921 inputblock.cn.push(input);
3923 inputblock.cn.push({
3925 cls : 'input-group-addon',
3932 if (align ==='left' && this.fieldLabel.length) {
3933 Roo.log("left and has label");
3939 cls : 'control-label col-sm-' + this.labelWidth,
3940 html : this.fieldLabel
3944 cls : "col-sm-" + (12 - this.labelWidth),
3951 } else if ( this.fieldLabel.length) {
3957 //cls : 'input-group-addon',
3958 html : this.fieldLabel
3968 Roo.log(" no label && no align");
3982 * return the real input element.
3984 inputEl: function ()
3986 return this.el.select('input.form-control',true).first();
3988 setDisabled : function(v)
3990 var i = this.inputEl().dom;
3992 i.removeAttribute('disabled');
3996 i.setAttribute('disabled','true');
3998 initEvents : function()
4001 this.inputEl().on("keydown" , this.fireKey, this);
4002 this.inputEl().on("focus", this.onFocus, this);
4003 this.inputEl().on("blur", this.onBlur, this);
4005 this.inputEl().relayEvent('keyup', this);
4007 // reference to original value for reset
4008 this.originalValue = this.getValue();
4009 //Roo.form.TextField.superclass.initEvents.call(this);
4010 if(this.validationEvent == 'keyup'){
4011 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
4012 this.inputEl().on('keyup', this.filterValidation, this);
4014 else if(this.validationEvent !== false){
4015 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
4018 if(this.selectOnFocus){
4019 this.on("focus", this.preFocus, this);
4022 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
4023 this.inputEl().on("keypress", this.filterKeys, this);
4026 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
4027 this.el.on("click", this.autoSize, this);
4030 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
4031 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
4035 filterValidation : function(e){
4036 if(!e.isNavKeyPress()){
4037 this.validationTask.delay(this.validationDelay);
4041 * Validates the field value
4042 * @return {Boolean} True if the value is valid, else false
4044 validate : function(){
4045 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
4046 if(this.disabled || this.validateValue(this.getRawValue())){
4047 this.clearInvalid();
4055 * Validates a value according to the field's validation rules and marks the field as invalid
4056 * if the validation fails
4057 * @param {Mixed} value The value to validate
4058 * @return {Boolean} True if the value is valid, else false
4060 validateValue : function(value){
4061 if(value.length < 1) { // if it's blank
4062 if(this.allowBlank){
4063 this.clearInvalid();
4066 this.markInvalid(this.blankText);
4070 if(value.length < this.minLength){
4071 this.markInvalid(String.format(this.minLengthText, this.minLength));
4074 if(value.length > this.maxLength){
4075 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
4079 var vt = Roo.form.VTypes;
4080 if(!vt[this.vtype](value, this)){
4081 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
4085 if(typeof this.validator == "function"){
4086 var msg = this.validator(value);
4088 this.markInvalid(msg);
4092 if(this.regex && !this.regex.test(value)){
4093 this.markInvalid(this.regexText);
4102 fireKey : function(e){
4103 //Roo.log('field ' + e.getKey());
4104 if(e.isNavKeyPress()){
4105 this.fireEvent("specialkey", this, e);
4108 focus : function (selectText){
4110 this.inputEl().focus();
4111 if(selectText === true){
4112 this.inputEl().dom.select();
4118 onFocus : function(){
4119 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4120 // this.el.addClass(this.focusClass);
4123 this.hasFocus = true;
4124 this.startValue = this.getValue();
4125 this.fireEvent("focus", this);
4129 beforeBlur : Roo.emptyFn,
4133 onBlur : function(){
4135 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4136 //this.el.removeClass(this.focusClass);
4138 this.hasFocus = false;
4139 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
4142 var v = this.getValue();
4143 if(String(v) !== String(this.startValue)){
4144 this.fireEvent('change', this, v, this.startValue);
4146 this.fireEvent("blur", this);
4150 * Resets the current field value to the originally loaded value and clears any validation messages
4153 this.setValue(this.originalValue);
4154 this.clearInvalid();
4157 * Returns the name of the field
4158 * @return {Mixed} name The name field
4160 getName: function(){
4164 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
4165 * @return {Mixed} value The field value
4167 getValue : function(){
4168 return this.inputEl().getValue();
4171 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
4172 * @return {Mixed} value The field value
4174 getRawValue : function(){
4175 var v = this.inputEl().getValue();
4181 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
4182 * @param {Mixed} value The value to set
4184 setRawValue : function(v){
4185 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4188 selectText : function(start, end){
4189 var v = this.getRawValue();
4191 start = start === undefined ? 0 : start;
4192 end = end === undefined ? v.length : end;
4193 var d = this.inputEl().dom;
4194 if(d.setSelectionRange){
4195 d.setSelectionRange(start, end);
4196 }else if(d.createTextRange){
4197 var range = d.createTextRange();
4198 range.moveStart("character", start);
4199 range.moveEnd("character", v.length-end);
4206 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
4207 * @param {Mixed} value The value to set
4209 setValue : function(v){
4212 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4218 processValue : function(value){
4219 if(this.stripCharsRe){
4220 var newValue = value.replace(this.stripCharsRe, '');
4221 if(newValue !== value){
4222 this.setRawValue(newValue);
4229 preFocus : function(){
4231 if(this.selectOnFocus){
4232 this.inputEl().dom.select();
4235 filterKeys : function(e){
4237 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
4240 var c = e.getCharCode(), cc = String.fromCharCode(c);
4241 if(Roo.isIE && (e.isSpecialKey() || !cc)){
4244 if(!this.maskRe.test(cc)){
4249 * Clear any invalid styles/messages for this field
4251 clearInvalid : function(){
4253 if(!this.el || this.preventMark){ // not rendered
4256 this.el.removeClass(this.invalidClass);
4258 switch(this.msgTarget){
4260 this.el.dom.qtip = '';
4263 this.el.dom.title = '';
4267 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
4272 this.errorIcon.dom.qtip = '';
4273 this.errorIcon.hide();
4274 this.un('resize', this.alignErrorIcon, this);
4278 var t = Roo.getDom(this.msgTarget);
4280 t.style.display = 'none';
4284 this.fireEvent('valid', this);
4287 * Mark this field as invalid
4288 * @param {String} msg The validation message
4290 markInvalid : function(msg){
4291 if(!this.el || this.preventMark){ // not rendered
4294 this.el.addClass(this.invalidClass);
4296 msg = msg || this.invalidText;
4297 switch(this.msgTarget){
4299 this.el.dom.qtip = msg;
4300 this.el.dom.qclass = 'x-form-invalid-tip';
4301 if(Roo.QuickTips){ // fix for floating editors interacting with DND
4302 Roo.QuickTips.enable();
4306 this.el.dom.title = msg;
4310 var elp = this.el.findParent('.x-form-element', 5, true);
4311 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
4312 this.errorEl.setWidth(elp.getWidth(true)-20);
4314 this.errorEl.update(msg);
4315 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
4318 if(!this.errorIcon){
4319 var elp = this.el.findParent('.x-form-element', 5, true);
4320 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
4322 this.alignErrorIcon();
4323 this.errorIcon.dom.qtip = msg;
4324 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
4325 this.errorIcon.show();
4326 this.on('resize', this.alignErrorIcon, this);
4329 var t = Roo.getDom(this.msgTarget);
4331 t.style.display = this.msgDisplay;
4335 this.fireEvent('invalid', this, msg);
4338 SafariOnKeyDown : function(event)
4340 // this is a workaround for a password hang bug on chrome/ webkit.
4342 var isSelectAll = false;
4344 if(this.inputEl().dom.selectionEnd > 0){
4345 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
4347 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
4348 event.preventDefault();
4353 if(isSelectAll){ // backspace and delete key
4355 event.preventDefault();
4356 // this is very hacky as keydown always get's upper case.
4358 var cc = String.fromCharCode(event.getCharCode());
4359 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
4375 * @class Roo.bootstrap.TextArea
4376 * @extends Roo.bootstrap.Input
4377 * Bootstrap TextArea class
4378 * @cfg {Number} cols Specifies the visible width of a text area
4379 * @cfg {Number} rows Specifies the visible number of lines in a text area
4380 * @cfg {Number} readOnly Specifies that a text area should be read-only
4381 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
4382 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
4383 * @cfg {string} html text
4386 * Create a new TextArea
4387 * @param {Object} config The config object
4390 Roo.bootstrap.TextArea = function(config){
4391 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
4395 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
4405 getAutoCreate : function(){
4407 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4418 value : this.value || '',
4419 html: this.html || '',
4420 cls : 'form-control',
4421 placeholder : this.placeholder || ''
4425 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4426 input.maxLength = this.maxLength;
4430 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
4434 input.cols = this.cols;
4437 if (this.readOnly) {
4438 input.readonly = true;
4442 input.name = this.name;
4446 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
4450 ['xs','sm','md','lg'].map(function(size){
4451 if (settings[size]) {
4452 cfg.cls += ' col-' + size + '-' + settings[size];
4456 var inputblock = input;
4458 if (this.before || this.after) {
4461 cls : 'input-group',
4465 inputblock.cn.push({
4467 cls : 'input-group-addon',
4471 inputblock.cn.push(input);
4473 inputblock.cn.push({
4475 cls : 'input-group-addon',
4482 if (align ==='left' && this.fieldLabel.length) {
4483 Roo.log("left and has label");
4489 cls : 'control-label col-sm-' + this.labelWidth,
4490 html : this.fieldLabel
4494 cls : "col-sm-" + (12 - this.labelWidth),
4501 } else if ( this.fieldLabel.length) {
4507 //cls : 'input-group-addon',
4508 html : this.fieldLabel
4518 Roo.log(" no label && no align");
4528 if (this.disabled) {
4529 input.disabled=true;
4536 * return the real textarea element.
4538 inputEl: function ()
4540 return this.el.select('textarea.form-control',true).first();
4548 * trigger field - base class for combo..
4553 * @class Roo.bootstrap.TriggerField
4554 * @extends Roo.bootstrap.Input
4555 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
4556 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
4557 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
4558 * for which you can provide a custom implementation. For example:
4560 var trigger = new Roo.bootstrap.TriggerField();
4561 trigger.onTriggerClick = myTriggerFn;
4562 trigger.applyTo('my-field');
4565 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
4566 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
4567 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
4568 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
4570 * Create a new TriggerField.
4571 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
4572 * to the base TextField)
4574 Roo.bootstrap.TriggerField = function(config){
4575 this.mimicing = false;
4576 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
4579 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
4581 * @cfg {String} triggerClass A CSS class to apply to the trigger
4584 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
4588 /** @cfg {Boolean} grow @hide */
4589 /** @cfg {Number} growMin @hide */
4590 /** @cfg {Number} growMax @hide */
4596 autoSize: Roo.emptyFn,
4603 actionMode : 'wrap',
4607 getAutoCreate : function(){
4609 var parent = this.parent();
4611 var align = this.parentLabelAlign();
4616 cls: 'form-group' //input-group
4623 type : this.inputType,
4624 cls : 'form-control',
4625 autocomplete: 'off',
4626 placeholder : this.placeholder || ''
4630 input.name = this.name;
4633 input.cls += ' input-' + this.size;
4636 cls: 'combobox-container input-group',
4641 cls: 'form-hidden-field'
4646 cls : 'typeahead typeahead-long dropdown-menu',
4647 style : 'display:none'
4651 cls : 'input-group-addon btn dropdown-toggle',
4659 cls: 'combobox-clear',
4676 if (align ==='left' && this.fieldLabel.length) {
4680 Roo.log("left and has label");
4686 cls : 'col-sm-2 control-label',
4687 html : this.fieldLabel
4698 } else if ( this.fieldLabel.length) {
4704 //cls : 'input-group-addon',
4705 html : this.fieldLabel
4715 Roo.log(" no label && no align");
4722 ['xs','sm','md','lg'].map(function(size){
4723 if (settings[size]) {
4724 cfg.cls += ' col-' + size + '-' + settings[size];
4730 if (this.disabled) {
4731 input.disabled=true;
4740 onResize : function(w, h){
4741 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
4742 // if(typeof w == 'number'){
4743 // var x = w - this.trigger.getWidth();
4744 // this.inputEl().setWidth(this.adjustWidth('input', x));
4745 // this.trigger.setStyle('left', x+'px');
4750 adjustSize : Roo.BoxComponent.prototype.adjustSize,
4753 getResizeEl : function(){
4754 return this.inputEl();
4758 getPositionEl : function(){
4759 return this.inputEl();
4763 alignErrorIcon : function(){
4764 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
4768 initEvents : function(){
4770 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
4771 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
4773 this.trigger = this.el.select('span.dropdown-toggle',true).first();
4774 if(this.hideTrigger){
4775 this.trigger.setDisplayed(false);
4777 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
4778 //this.trigger.addClassOnOver('x-form-trigger-over');
4779 //this.trigger.addClassOnClick('x-form-trigger-click');
4782 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
4787 initTrigger : function(){
4792 onDestroy : function(){
4794 this.trigger.removeAllListeners();
4795 // this.trigger.remove();
4798 // this.wrap.remove();
4800 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
4804 onFocus : function(){
4805 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
4808 this.wrap.addClass('x-trigger-wrap-focus');
4809 this.mimicing = true;
4810 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
4811 if(this.monitorTab){
4812 this.el.on("keydown", this.checkTab, this);
4819 checkTab : function(e){
4820 if(e.getKey() == e.TAB){
4826 onBlur : function(){
4831 mimicBlur : function(e, t){
4833 if(!this.wrap.contains(t) && this.validateBlur()){
4840 triggerBlur : function(){
4841 this.mimicing = false;
4842 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
4843 if(this.monitorTab){
4844 this.el.un("keydown", this.checkTab, this);
4846 //this.wrap.removeClass('x-trigger-wrap-focus');
4847 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
4851 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
4852 validateBlur : function(e, t){
4857 onDisable : function(){
4858 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
4860 // this.wrap.addClass('x-item-disabled');
4865 onEnable : function(){
4866 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
4868 // this.el.removeClass('x-item-disabled');
4873 onShow : function(){
4874 var ae = this.getActionEl();
4877 ae.dom.style.display = '';
4878 ae.dom.style.visibility = 'visible';
4884 onHide : function(){
4885 var ae = this.getActionEl();
4886 ae.dom.style.display = 'none';
4890 * The function that should handle the trigger's click event. This method does nothing by default until overridden
4891 * by an implementing function.
4893 * @param {EventObject} e
4895 onTriggerClick : Roo.emptyFn
4899 * Ext JS Library 1.1.1
4900 * Copyright(c) 2006-2007, Ext JS, LLC.
4902 * Originally Released Under LGPL - original licence link has changed is not relivant.
4905 * <script type="text/javascript">
4910 * @class Roo.data.SortTypes
4912 * Defines the default sorting (casting?) comparison functions used when sorting data.
4914 Roo.data.SortTypes = {
4916 * Default sort that does nothing
4917 * @param {Mixed} s The value being converted
4918 * @return {Mixed} The comparison value
4925 * The regular expression used to strip tags
4929 stripTagsRE : /<\/?[^>]+>/gi,
4932 * Strips all HTML tags to sort on text only
4933 * @param {Mixed} s The value being converted
4934 * @return {String} The comparison value
4936 asText : function(s){
4937 return String(s).replace(this.stripTagsRE, "");
4941 * Strips all HTML tags to sort on text only - Case insensitive
4942 * @param {Mixed} s The value being converted
4943 * @return {String} The comparison value
4945 asUCText : function(s){
4946 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4950 * Case insensitive string
4951 * @param {Mixed} s The value being converted
4952 * @return {String} The comparison value
4954 asUCString : function(s) {
4955 return String(s).toUpperCase();
4960 * @param {Mixed} s The value being converted
4961 * @return {Number} The comparison value
4963 asDate : function(s) {
4967 if(s instanceof Date){
4970 return Date.parse(String(s));
4975 * @param {Mixed} s The value being converted
4976 * @return {Float} The comparison value
4978 asFloat : function(s) {
4979 var val = parseFloat(String(s).replace(/,/g, ""));
4980 if(isNaN(val)) val = 0;
4986 * @param {Mixed} s The value being converted
4987 * @return {Number} The comparison value
4989 asInt : function(s) {
4990 var val = parseInt(String(s).replace(/,/g, ""));
4991 if(isNaN(val)) val = 0;
4996 * Ext JS Library 1.1.1
4997 * Copyright(c) 2006-2007, Ext JS, LLC.
4999 * Originally Released Under LGPL - original licence link has changed is not relivant.
5002 * <script type="text/javascript">
5006 * @class Roo.data.Record
5007 * Instances of this class encapsulate both record <em>definition</em> information, and record
5008 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
5009 * to access Records cached in an {@link Roo.data.Store} object.<br>
5011 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
5012 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
5015 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
5017 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
5018 * {@link #create}. The parameters are the same.
5019 * @param {Array} data An associative Array of data values keyed by the field name.
5020 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
5021 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
5022 * not specified an integer id is generated.
5024 Roo.data.Record = function(data, id){
5025 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
5030 * Generate a constructor for a specific record layout.
5031 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
5032 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
5033 * Each field definition object may contain the following properties: <ul>
5034 * <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,
5035 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
5036 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
5037 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
5038 * is being used, then this is a string containing the javascript expression to reference the data relative to
5039 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
5040 * to the data item relative to the record element. If the mapping expression is the same as the field name,
5041 * this may be omitted.</p></li>
5042 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
5043 * <ul><li>auto (Default, implies no conversion)</li>
5048 * <li>date</li></ul></p></li>
5049 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
5050 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
5051 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
5052 * by the Reader into an object that will be stored in the Record. It is passed the
5053 * following parameters:<ul>
5054 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
5056 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
5058 * <br>usage:<br><pre><code>
5059 var TopicRecord = Roo.data.Record.create(
5060 {name: 'title', mapping: 'topic_title'},
5061 {name: 'author', mapping: 'username'},
5062 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
5063 {name: 'lastPost', mapping: 'post_time', type: 'date'},
5064 {name: 'lastPoster', mapping: 'user2'},
5065 {name: 'excerpt', mapping: 'post_text'}
5068 var myNewRecord = new TopicRecord({
5069 title: 'Do my job please',
5072 lastPost: new Date(),
5073 lastPoster: 'Animal',
5074 excerpt: 'No way dude!'
5076 myStore.add(myNewRecord);
5081 Roo.data.Record.create = function(o){
5083 f.superclass.constructor.apply(this, arguments);
5085 Roo.extend(f, Roo.data.Record);
5086 var p = f.prototype;
5087 p.fields = new Roo.util.MixedCollection(false, function(field){
5090 for(var i = 0, len = o.length; i < len; i++){
5091 p.fields.add(new Roo.data.Field(o[i]));
5093 f.getField = function(name){
5094 return p.fields.get(name);
5099 Roo.data.Record.AUTO_ID = 1000;
5100 Roo.data.Record.EDIT = 'edit';
5101 Roo.data.Record.REJECT = 'reject';
5102 Roo.data.Record.COMMIT = 'commit';
5104 Roo.data.Record.prototype = {
5106 * Readonly flag - true if this record has been modified.
5115 join : function(store){
5120 * Set the named field to the specified value.
5121 * @param {String} name The name of the field to set.
5122 * @param {Object} value The value to set the field to.
5124 set : function(name, value){
5125 if(this.data[name] == value){
5132 if(typeof this.modified[name] == 'undefined'){
5133 this.modified[name] = this.data[name];
5135 this.data[name] = value;
5136 if(!this.editing && this.store){
5137 this.store.afterEdit(this);
5142 * Get the value of the named field.
5143 * @param {String} name The name of the field to get the value of.
5144 * @return {Object} The value of the field.
5146 get : function(name){
5147 return this.data[name];
5151 beginEdit : function(){
5152 this.editing = true;
5157 cancelEdit : function(){
5158 this.editing = false;
5159 delete this.modified;
5163 endEdit : function(){
5164 this.editing = false;
5165 if(this.dirty && this.store){
5166 this.store.afterEdit(this);
5171 * Usually called by the {@link Roo.data.Store} which owns the Record.
5172 * Rejects all changes made to the Record since either creation, or the last commit operation.
5173 * Modified fields are reverted to their original values.
5175 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5176 * of reject operations.
5178 reject : function(){
5179 var m = this.modified;
5181 if(typeof m[n] != "function"){
5182 this.data[n] = m[n];
5186 delete this.modified;
5187 this.editing = false;
5189 this.store.afterReject(this);
5194 * Usually called by the {@link Roo.data.Store} which owns the Record.
5195 * Commits all changes made to the Record since either creation, or the last commit operation.
5197 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5198 * of commit operations.
5200 commit : function(){
5202 delete this.modified;
5203 this.editing = false;
5205 this.store.afterCommit(this);
5210 hasError : function(){
5211 return this.error != null;
5215 clearError : function(){
5220 * Creates a copy of this record.
5221 * @param {String} id (optional) A new record id if you don't want to use this record's id
5224 copy : function(newId) {
5225 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
5229 * Ext JS Library 1.1.1
5230 * Copyright(c) 2006-2007, Ext JS, LLC.
5232 * Originally Released Under LGPL - original licence link has changed is not relivant.
5235 * <script type="text/javascript">
5241 * @class Roo.data.Store
5242 * @extends Roo.util.Observable
5243 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
5244 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
5246 * 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
5247 * has no knowledge of the format of the data returned by the Proxy.<br>
5249 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
5250 * instances from the data object. These records are cached and made available through accessor functions.
5252 * Creates a new Store.
5253 * @param {Object} config A config object containing the objects needed for the Store to access data,
5254 * and read the data into Records.
5256 Roo.data.Store = function(config){
5257 this.data = new Roo.util.MixedCollection(false);
5258 this.data.getKey = function(o){
5261 this.baseParams = {};
5268 "multisort" : "_multisort"
5271 if(config && config.data){
5272 this.inlineData = config.data;
5276 Roo.apply(this, config);
5278 if(this.reader){ // reader passed
5279 this.reader = Roo.factory(this.reader, Roo.data);
5280 this.reader.xmodule = this.xmodule || false;
5281 if(!this.recordType){
5282 this.recordType = this.reader.recordType;
5284 if(this.reader.onMetaChange){
5285 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
5289 if(this.recordType){
5290 this.fields = this.recordType.prototype.fields;
5296 * @event datachanged
5297 * Fires when the data cache has changed, and a widget which is using this Store
5298 * as a Record cache should refresh its view.
5299 * @param {Store} this
5304 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
5305 * @param {Store} this
5306 * @param {Object} meta The JSON metadata
5311 * Fires when Records have been added to the Store
5312 * @param {Store} this
5313 * @param {Roo.data.Record[]} records The array of Records added
5314 * @param {Number} index The index at which the record(s) were added
5319 * Fires when a Record has been removed from the Store
5320 * @param {Store} this
5321 * @param {Roo.data.Record} record The Record that was removed
5322 * @param {Number} index The index at which the record was removed
5327 * Fires when a Record has been updated
5328 * @param {Store} this
5329 * @param {Roo.data.Record} record The Record that was updated
5330 * @param {String} operation The update operation being performed. Value may be one of:
5332 Roo.data.Record.EDIT
5333 Roo.data.Record.REJECT
5334 Roo.data.Record.COMMIT
5340 * Fires when the data cache has been cleared.
5341 * @param {Store} this
5346 * Fires before a request is made for a new data object. If the beforeload handler returns false
5347 * the load action will be canceled.
5348 * @param {Store} this
5349 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5353 * @event beforeloadadd
5354 * Fires after a new set of Records has been loaded.
5355 * @param {Store} this
5356 * @param {Roo.data.Record[]} records The Records that were loaded
5357 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5359 beforeloadadd : true,
5362 * Fires after a new set of Records has been loaded, before they are added to the store.
5363 * @param {Store} this
5364 * @param {Roo.data.Record[]} records The Records that were loaded
5365 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5366 * @params {Object} return from reader
5370 * @event loadexception
5371 * Fires if an exception occurs in the Proxy during loading.
5372 * Called with the signature of the Proxy's "loadexception" event.
5373 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
5376 * @param {Object} return from JsonData.reader() - success, totalRecords, records
5377 * @param {Object} load options
5378 * @param {Object} jsonData from your request (normally this contains the Exception)
5380 loadexception : true
5384 this.proxy = Roo.factory(this.proxy, Roo.data);
5385 this.proxy.xmodule = this.xmodule || false;
5386 this.relayEvents(this.proxy, ["loadexception"]);
5388 this.sortToggle = {};
5389 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
5391 Roo.data.Store.superclass.constructor.call(this);
5393 if(this.inlineData){
5394 this.loadData(this.inlineData);
5395 delete this.inlineData;
5399 Roo.extend(Roo.data.Store, Roo.util.Observable, {
5401 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
5402 * without a remote query - used by combo/forms at present.
5406 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
5409 * @cfg {Array} data Inline data to be loaded when the store is initialized.
5412 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
5413 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
5416 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
5417 * on any HTTP request
5420 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
5423 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
5427 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
5428 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
5433 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
5434 * loaded or when a record is removed. (defaults to false).
5436 pruneModifiedRecords : false,
5442 * Add Records to the Store and fires the add event.
5443 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
5445 add : function(records){
5446 records = [].concat(records);
5447 for(var i = 0, len = records.length; i < len; i++){
5448 records[i].join(this);
5450 var index = this.data.length;
5451 this.data.addAll(records);
5452 this.fireEvent("add", this, records, index);
5456 * Remove a Record from the Store and fires the remove event.
5457 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
5459 remove : function(record){
5460 var index = this.data.indexOf(record);
5461 this.data.removeAt(index);
5462 if(this.pruneModifiedRecords){
5463 this.modified.remove(record);
5465 this.fireEvent("remove", this, record, index);
5469 * Remove all Records from the Store and fires the clear event.
5471 removeAll : function(){
5473 if(this.pruneModifiedRecords){
5476 this.fireEvent("clear", this);
5480 * Inserts Records to the Store at the given index and fires the add event.
5481 * @param {Number} index The start index at which to insert the passed Records.
5482 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
5484 insert : function(index, records){
5485 records = [].concat(records);
5486 for(var i = 0, len = records.length; i < len; i++){
5487 this.data.insert(index, records[i]);
5488 records[i].join(this);
5490 this.fireEvent("add", this, records, index);
5494 * Get the index within the cache of the passed Record.
5495 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
5496 * @return {Number} The index of the passed Record. Returns -1 if not found.
5498 indexOf : function(record){
5499 return this.data.indexOf(record);
5503 * Get the index within the cache of the Record with the passed id.
5504 * @param {String} id The id of the Record to find.
5505 * @return {Number} The index of the Record. Returns -1 if not found.
5507 indexOfId : function(id){
5508 return this.data.indexOfKey(id);
5512 * Get the Record with the specified id.
5513 * @param {String} id The id of the Record to find.
5514 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
5516 getById : function(id){
5517 return this.data.key(id);
5521 * Get the Record at the specified index.
5522 * @param {Number} index The index of the Record to find.
5523 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
5525 getAt : function(index){
5526 return this.data.itemAt(index);
5530 * Returns a range of Records between specified indices.
5531 * @param {Number} startIndex (optional) The starting index (defaults to 0)
5532 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
5533 * @return {Roo.data.Record[]} An array of Records
5535 getRange : function(start, end){
5536 return this.data.getRange(start, end);
5540 storeOptions : function(o){
5541 o = Roo.apply({}, o);
5544 this.lastOptions = o;
5548 * Loads the Record cache from the configured Proxy using the configured Reader.
5550 * If using remote paging, then the first load call must specify the <em>start</em>
5551 * and <em>limit</em> properties in the options.params property to establish the initial
5552 * position within the dataset, and the number of Records to cache on each read from the Proxy.
5554 * <strong>It is important to note that for remote data sources, loading is asynchronous,
5555 * and this call will return before the new data has been loaded. Perform any post-processing
5556 * in a callback function, or in a "load" event handler.</strong>
5558 * @param {Object} options An object containing properties which control loading options:<ul>
5559 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
5560 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
5561 * passed the following arguments:<ul>
5562 * <li>r : Roo.data.Record[]</li>
5563 * <li>options: Options object from the load call</li>
5564 * <li>success: Boolean success indicator</li></ul></li>
5565 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
5566 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
5569 load : function(options){
5570 options = options || {};
5571 if(this.fireEvent("beforeload", this, options) !== false){
5572 this.storeOptions(options);
5573 var p = Roo.apply(options.params || {}, this.baseParams);
5574 // if meta was not loaded from remote source.. try requesting it.
5575 if (!this.reader.metaFromRemote) {
5578 if(this.sortInfo && this.remoteSort){
5579 var pn = this.paramNames;
5580 p[pn["sort"]] = this.sortInfo.field;
5581 p[pn["dir"]] = this.sortInfo.direction;
5583 if (this.multiSort) {
5584 var pn = this.paramNames;
5585 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
5588 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5593 * Reloads the Record cache from the configured Proxy using the configured Reader and
5594 * the options from the last load operation performed.
5595 * @param {Object} options (optional) An object containing properties which may override the options
5596 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5597 * the most recently used options are reused).
5599 reload : function(options){
5600 this.load(Roo.applyIf(options||{}, this.lastOptions));
5604 // Called as a callback by the Reader during a load operation.
5605 loadRecords : function(o, options, success){
5606 if(!o || success === false){
5607 if(success !== false){
5608 this.fireEvent("load", this, [], options, o);
5610 if(options.callback){
5611 options.callback.call(options.scope || this, [], options, false);
5615 // if data returned failure - throw an exception.
5616 if (o.success === false) {
5617 // show a message if no listener is registered.
5618 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
5619 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
5621 // loadmask wil be hooked into this..
5622 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
5625 var r = o.records, t = o.totalRecords || r.length;
5627 this.fireEvent("beforeloadadd", this, r, options, o);
5629 if(!options || options.add !== true){
5630 if(this.pruneModifiedRecords){
5633 for(var i = 0, len = r.length; i < len; i++){
5637 this.data = this.snapshot;
5638 delete this.snapshot;
5641 this.data.addAll(r);
5642 this.totalLength = t;
5644 this.fireEvent("datachanged", this);
5646 this.totalLength = Math.max(t, this.data.length+r.length);
5649 this.fireEvent("load", this, r, options, o);
5650 if(options.callback){
5651 options.callback.call(options.scope || this, r, options, true);
5657 * Loads data from a passed data block. A Reader which understands the format of the data
5658 * must have been configured in the constructor.
5659 * @param {Object} data The data block from which to read the Records. The format of the data expected
5660 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5661 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5663 loadData : function(o, append){
5664 var r = this.reader.readRecords(o);
5665 this.loadRecords(r, {add: append}, true);
5669 * Gets the number of cached records.
5671 * <em>If using paging, this may not be the total size of the dataset. If the data object
5672 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5673 * the data set size</em>
5675 getCount : function(){
5676 return this.data.length || 0;
5680 * Gets the total number of records in the dataset as returned by the server.
5682 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5683 * the dataset size</em>
5685 getTotalCount : function(){
5686 return this.totalLength || 0;
5690 * Returns the sort state of the Store as an object with two properties:
5692 field {String} The name of the field by which the Records are sorted
5693 direction {String} The sort order, "ASC" or "DESC"
5696 getSortState : function(){
5697 return this.sortInfo;
5701 applySort : function(){
5702 if(this.sortInfo && !this.remoteSort){
5703 var s = this.sortInfo, f = s.field;
5704 var st = this.fields.get(f).sortType;
5705 var fn = function(r1, r2){
5706 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5707 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5709 this.data.sort(s.direction, fn);
5710 if(this.snapshot && this.snapshot != this.data){
5711 this.snapshot.sort(s.direction, fn);
5717 * Sets the default sort column and order to be used by the next load operation.
5718 * @param {String} fieldName The name of the field to sort by.
5719 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5721 setDefaultSort : function(field, dir){
5722 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5727 * If remote sorting is used, the sort is performed on the server, and the cache is
5728 * reloaded. If local sorting is used, the cache is sorted internally.
5729 * @param {String} fieldName The name of the field to sort by.
5730 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5732 sort : function(fieldName, dir){
5733 var f = this.fields.get(fieldName);
5735 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
5737 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
5738 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5743 this.sortToggle[f.name] = dir;
5744 this.sortInfo = {field: f.name, direction: dir};
5745 if(!this.remoteSort){
5747 this.fireEvent("datachanged", this);
5749 this.load(this.lastOptions);
5754 * Calls the specified function for each of the Records in the cache.
5755 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5756 * Returning <em>false</em> aborts and exits the iteration.
5757 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5759 each : function(fn, scope){
5760 this.data.each(fn, scope);
5764 * Gets all records modified since the last commit. Modified records are persisted across load operations
5765 * (e.g., during paging).
5766 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5768 getModifiedRecords : function(){
5769 return this.modified;
5773 createFilterFn : function(property, value, anyMatch){
5774 if(!value.exec){ // not a regex
5775 value = String(value);
5776 if(value.length == 0){
5779 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5782 return value.test(r.data[property]);
5787 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5788 * @param {String} property A field on your records
5789 * @param {Number} start The record index to start at (defaults to 0)
5790 * @param {Number} end The last record index to include (defaults to length - 1)
5791 * @return {Number} The sum
5793 sum : function(property, start, end){
5794 var rs = this.data.items, v = 0;
5796 end = (end || end === 0) ? end : rs.length-1;
5798 for(var i = start; i <= end; i++){
5799 v += (rs[i].data[property] || 0);
5805 * Filter the records by a specified property.
5806 * @param {String} field A field on your records
5807 * @param {String/RegExp} value Either a string that the field
5808 * should start with or a RegExp to test against the field
5809 * @param {Boolean} anyMatch True to match any part not just the beginning
5811 filter : function(property, value, anyMatch){
5812 var fn = this.createFilterFn(property, value, anyMatch);
5813 return fn ? this.filterBy(fn) : this.clearFilter();
5817 * Filter by a function. The specified function will be called with each
5818 * record in this data source. If the function returns true the record is included,
5819 * otherwise it is filtered.
5820 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5821 * @param {Object} scope (optional) The scope of the function (defaults to this)
5823 filterBy : function(fn, scope){
5824 this.snapshot = this.snapshot || this.data;
5825 this.data = this.queryBy(fn, scope||this);
5826 this.fireEvent("datachanged", this);
5830 * Query the records by a specified property.
5831 * @param {String} field A field on your records
5832 * @param {String/RegExp} value Either a string that the field
5833 * should start with or a RegExp to test against the field
5834 * @param {Boolean} anyMatch True to match any part not just the beginning
5835 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5837 query : function(property, value, anyMatch){
5838 var fn = this.createFilterFn(property, value, anyMatch);
5839 return fn ? this.queryBy(fn) : this.data.clone();
5843 * Query by a function. The specified function will be called with each
5844 * record in this data source. If the function returns true the record is included
5846 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5847 * @param {Object} scope (optional) The scope of the function (defaults to this)
5848 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5850 queryBy : function(fn, scope){
5851 var data = this.snapshot || this.data;
5852 return data.filterBy(fn, scope||this);
5856 * Collects unique values for a particular dataIndex from this store.
5857 * @param {String} dataIndex The property to collect
5858 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5859 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5860 * @return {Array} An array of the unique values
5862 collect : function(dataIndex, allowNull, bypassFilter){
5863 var d = (bypassFilter === true && this.snapshot) ?
5864 this.snapshot.items : this.data.items;
5865 var v, sv, r = [], l = {};
5866 for(var i = 0, len = d.length; i < len; i++){
5867 v = d[i].data[dataIndex];
5869 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5878 * Revert to a view of the Record cache with no filtering applied.
5879 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5881 clearFilter : function(suppressEvent){
5882 if(this.snapshot && this.snapshot != this.data){
5883 this.data = this.snapshot;
5884 delete this.snapshot;
5885 if(suppressEvent !== true){
5886 this.fireEvent("datachanged", this);
5892 afterEdit : function(record){
5893 if(this.modified.indexOf(record) == -1){
5894 this.modified.push(record);
5896 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5900 afterReject : function(record){
5901 this.modified.remove(record);
5902 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5906 afterCommit : function(record){
5907 this.modified.remove(record);
5908 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5912 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5913 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5915 commitChanges : function(){
5916 var m = this.modified.slice(0);
5918 for(var i = 0, len = m.length; i < len; i++){
5924 * Cancel outstanding changes on all changed records.
5926 rejectChanges : function(){
5927 var m = this.modified.slice(0);
5929 for(var i = 0, len = m.length; i < len; i++){
5934 onMetaChange : function(meta, rtype, o){
5935 this.recordType = rtype;
5936 this.fields = rtype.prototype.fields;
5937 delete this.snapshot;
5938 this.sortInfo = meta.sortInfo || this.sortInfo;
5940 this.fireEvent('metachange', this, this.reader.meta);
5944 * Ext JS Library 1.1.1
5945 * Copyright(c) 2006-2007, Ext JS, LLC.
5947 * Originally Released Under LGPL - original licence link has changed is not relivant.
5950 * <script type="text/javascript">
5954 * @class Roo.data.SimpleStore
5955 * @extends Roo.data.Store
5956 * Small helper class to make creating Stores from Array data easier.
5957 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5958 * @cfg {Array} fields An array of field definition objects, or field name strings.
5959 * @cfg {Array} data The multi-dimensional array of data
5961 * @param {Object} config
5963 Roo.data.SimpleStore = function(config){
5964 Roo.data.SimpleStore.superclass.constructor.call(this, {
5966 reader: new Roo.data.ArrayReader({
5969 Roo.data.Record.create(config.fields)
5971 proxy : new Roo.data.MemoryProxy(config.data)
5975 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5977 * Ext JS Library 1.1.1
5978 * Copyright(c) 2006-2007, Ext JS, LLC.
5980 * Originally Released Under LGPL - original licence link has changed is not relivant.
5983 * <script type="text/javascript">
5988 * @extends Roo.data.Store
5989 * @class Roo.data.JsonStore
5990 * Small helper class to make creating Stores for JSON data easier. <br/>
5992 var store = new Roo.data.JsonStore({
5993 url: 'get-images.php',
5995 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5998 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5999 * JsonReader and HttpProxy (unless inline data is provided).</b>
6000 * @cfg {Array} fields An array of field definition objects, or field name strings.
6002 * @param {Object} config
6004 Roo.data.JsonStore = function(c){
6005 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
6006 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
6007 reader: new Roo.data.JsonReader(c, c.fields)
6010 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
6012 * Ext JS Library 1.1.1
6013 * Copyright(c) 2006-2007, Ext JS, LLC.
6015 * Originally Released Under LGPL - original licence link has changed is not relivant.
6018 * <script type="text/javascript">
6022 Roo.data.Field = function(config){
6023 if(typeof config == "string"){
6024 config = {name: config};
6026 Roo.apply(this, config);
6032 var st = Roo.data.SortTypes;
6033 // named sortTypes are supported, here we look them up
6034 if(typeof this.sortType == "string"){
6035 this.sortType = st[this.sortType];
6038 // set default sortType for strings and dates
6042 this.sortType = st.asUCString;
6045 this.sortType = st.asDate;
6048 this.sortType = st.none;
6053 var stripRe = /[\$,%]/g;
6055 // prebuilt conversion function for this field, instead of
6056 // switching every time we're reading a value
6058 var cv, dateFormat = this.dateFormat;
6063 cv = function(v){ return v; };
6066 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
6070 return v !== undefined && v !== null && v !== '' ?
6071 parseInt(String(v).replace(stripRe, ""), 10) : '';
6076 return v !== undefined && v !== null && v !== '' ?
6077 parseFloat(String(v).replace(stripRe, ""), 10) : '';
6082 cv = function(v){ return v === true || v === "true" || v == 1; };
6089 if(v instanceof Date){
6093 if(dateFormat == "timestamp"){
6094 return new Date(v*1000);
6096 return Date.parseDate(v, dateFormat);
6098 var parsed = Date.parse(v);
6099 return parsed ? new Date(parsed) : null;
6108 Roo.data.Field.prototype = {
6116 * Ext JS Library 1.1.1
6117 * Copyright(c) 2006-2007, Ext JS, LLC.
6119 * Originally Released Under LGPL - original licence link has changed is not relivant.
6122 * <script type="text/javascript">
6125 // Base class for reading structured data from a data source. This class is intended to be
6126 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
6129 * @class Roo.data.DataReader
6130 * Base class for reading structured data from a data source. This class is intended to be
6131 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
6134 Roo.data.DataReader = function(meta, recordType){
6138 this.recordType = recordType instanceof Array ?
6139 Roo.data.Record.create(recordType) : recordType;
6142 Roo.data.DataReader.prototype = {
6144 * Create an empty record
6145 * @param {Object} data (optional) - overlay some values
6146 * @return {Roo.data.Record} record created.
6148 newRow : function(d) {
6150 this.recordType.prototype.fields.each(function(c) {
6152 case 'int' : da[c.name] = 0; break;
6153 case 'date' : da[c.name] = new Date(); break;
6154 case 'float' : da[c.name] = 0.0; break;
6155 case 'boolean' : da[c.name] = false; break;
6156 default : da[c.name] = ""; break;
6160 return new this.recordType(Roo.apply(da, d));
6165 * Ext JS Library 1.1.1
6166 * Copyright(c) 2006-2007, Ext JS, LLC.
6168 * Originally Released Under LGPL - original licence link has changed is not relivant.
6171 * <script type="text/javascript">
6175 * @class Roo.data.DataProxy
6176 * @extends Roo.data.Observable
6177 * This class is an abstract base class for implementations which provide retrieval of
6178 * unformatted data objects.<br>
6180 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
6181 * (of the appropriate type which knows how to parse the data object) to provide a block of
6182 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
6184 * Custom implementations must implement the load method as described in
6185 * {@link Roo.data.HttpProxy#load}.
6187 Roo.data.DataProxy = function(){
6191 * Fires before a network request is made to retrieve a data object.
6192 * @param {Object} This DataProxy object.
6193 * @param {Object} params The params parameter to the load function.
6198 * Fires before the load method's callback is called.
6199 * @param {Object} This DataProxy object.
6200 * @param {Object} o The data object.
6201 * @param {Object} arg The callback argument object passed to the load function.
6205 * @event loadexception
6206 * Fires if an Exception occurs during data retrieval.
6207 * @param {Object} This DataProxy object.
6208 * @param {Object} o The data object.
6209 * @param {Object} arg The callback argument object passed to the load function.
6210 * @param {Object} e The Exception.
6212 loadexception : true
6214 Roo.data.DataProxy.superclass.constructor.call(this);
6217 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
6220 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
6224 * Ext JS Library 1.1.1
6225 * Copyright(c) 2006-2007, Ext JS, LLC.
6227 * Originally Released Under LGPL - original licence link has changed is not relivant.
6230 * <script type="text/javascript">
6233 * @class Roo.data.MemoryProxy
6234 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
6235 * to the Reader when its load method is called.
6237 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
6239 Roo.data.MemoryProxy = function(data){
6243 Roo.data.MemoryProxy.superclass.constructor.call(this);
6247 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
6249 * Load data from the requested source (in this case an in-memory
6250 * data object passed to the constructor), read the data object into
6251 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6252 * process that block using the passed callback.
6253 * @param {Object} params This parameter is not used by the MemoryProxy class.
6254 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6255 * object into a block of Roo.data.Records.
6256 * @param {Function} callback The function into which to pass the block of Roo.data.records.
6257 * The function must be passed <ul>
6258 * <li>The Record block object</li>
6259 * <li>The "arg" argument from the load function</li>
6260 * <li>A boolean success indicator</li>
6262 * @param {Object} scope The scope in which to call the callback
6263 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6265 load : function(params, reader, callback, scope, arg){
6266 params = params || {};
6269 result = reader.readRecords(this.data);
6271 this.fireEvent("loadexception", this, arg, null, e);
6272 callback.call(scope, null, arg, false);
6275 callback.call(scope, result, arg, true);
6279 update : function(params, records){
6284 * Ext JS Library 1.1.1
6285 * Copyright(c) 2006-2007, Ext JS, LLC.
6287 * Originally Released Under LGPL - original licence link has changed is not relivant.
6290 * <script type="text/javascript">
6293 * @class Roo.data.HttpProxy
6294 * @extends Roo.data.DataProxy
6295 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
6296 * configured to reference a certain URL.<br><br>
6298 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
6299 * from which the running page was served.<br><br>
6301 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
6303 * Be aware that to enable the browser to parse an XML document, the server must set
6304 * the Content-Type header in the HTTP response to "text/xml".
6306 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
6307 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
6308 * will be used to make the request.
6310 Roo.data.HttpProxy = function(conn){
6311 Roo.data.HttpProxy.superclass.constructor.call(this);
6312 // is conn a conn config or a real conn?
6314 this.useAjax = !conn || !conn.events;
6318 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
6319 // thse are take from connection...
6322 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
6325 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
6326 * extra parameters to each request made by this object. (defaults to undefined)
6329 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
6330 * to each request made by this object. (defaults to undefined)
6333 * @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)
6336 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
6339 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
6345 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
6349 * Return the {@link Roo.data.Connection} object being used by this Proxy.
6350 * @return {Connection} The Connection object. This object may be used to subscribe to events on
6351 * a finer-grained basis than the DataProxy events.
6353 getConnection : function(){
6354 return this.useAjax ? Roo.Ajax : this.conn;
6358 * Load data from the configured {@link Roo.data.Connection}, read the data object into
6359 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
6360 * process that block using the passed callback.
6361 * @param {Object} params An object containing properties which are to be used as HTTP parameters
6362 * for the request to the remote server.
6363 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6364 * object into a block of Roo.data.Records.
6365 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6366 * The function must be passed <ul>
6367 * <li>The Record block object</li>
6368 * <li>The "arg" argument from the load function</li>
6369 * <li>A boolean success indicator</li>
6371 * @param {Object} scope The scope in which to call the callback
6372 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6374 load : function(params, reader, callback, scope, arg){
6375 if(this.fireEvent("beforeload", this, params) !== false){
6377 params : params || {},
6379 callback : callback,
6384 callback : this.loadResponse,
6388 Roo.applyIf(o, this.conn);
6389 if(this.activeRequest){
6390 Roo.Ajax.abort(this.activeRequest);
6392 this.activeRequest = Roo.Ajax.request(o);
6394 this.conn.request(o);
6397 callback.call(scope||this, null, arg, false);
6402 loadResponse : function(o, success, response){
6403 delete this.activeRequest;
6405 this.fireEvent("loadexception", this, o, response);
6406 o.request.callback.call(o.request.scope, null, o.request.arg, false);
6411 result = o.reader.read(response);
6413 this.fireEvent("loadexception", this, o, response, e);
6414 o.request.callback.call(o.request.scope, null, o.request.arg, false);
6418 this.fireEvent("load", this, o, o.request.arg);
6419 o.request.callback.call(o.request.scope, result, o.request.arg, true);
6423 update : function(dataSet){
6428 updateResponse : function(dataSet){
6433 * Ext JS Library 1.1.1
6434 * Copyright(c) 2006-2007, Ext JS, LLC.
6436 * Originally Released Under LGPL - original licence link has changed is not relivant.
6439 * <script type="text/javascript">
6443 * @class Roo.data.ScriptTagProxy
6444 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
6445 * other than the originating domain of the running page.<br><br>
6447 * <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
6448 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
6450 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
6451 * source code that is used as the source inside a <script> tag.<br><br>
6453 * In order for the browser to process the returned data, the server must wrap the data object
6454 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
6455 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
6456 * depending on whether the callback name was passed:
6459 boolean scriptTag = false;
6460 String cb = request.getParameter("callback");
6463 response.setContentType("text/javascript");
6465 response.setContentType("application/x-json");
6467 Writer out = response.getWriter();
6469 out.write(cb + "(");
6471 out.print(dataBlock.toJsonString());
6478 * @param {Object} config A configuration object.
6480 Roo.data.ScriptTagProxy = function(config){
6481 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
6482 Roo.apply(this, config);
6483 this.head = document.getElementsByTagName("head")[0];
6486 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
6488 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
6490 * @cfg {String} url The URL from which to request the data object.
6493 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
6497 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
6498 * the server the name of the callback function set up by the load call to process the returned data object.
6499 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
6500 * javascript output which calls this named function passing the data object as its only parameter.
6502 callbackParam : "callback",
6504 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
6505 * name to the request.
6510 * Load data from the configured URL, read the data object into
6511 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6512 * process that block using the passed callback.
6513 * @param {Object} params An object containing properties which are to be used as HTTP parameters
6514 * for the request to the remote server.
6515 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6516 * object into a block of Roo.data.Records.
6517 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6518 * The function must be passed <ul>
6519 * <li>The Record block object</li>
6520 * <li>The "arg" argument from the load function</li>
6521 * <li>A boolean success indicator</li>
6523 * @param {Object} scope The scope in which to call the callback
6524 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6526 load : function(params, reader, callback, scope, arg){
6527 if(this.fireEvent("beforeload", this, params) !== false){
6529 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
6532 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
6534 url += "&_dc=" + (new Date().getTime());
6536 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
6539 cb : "stcCallback"+transId,
6540 scriptId : "stcScript"+transId,
6544 callback : callback,
6550 window[trans.cb] = function(o){
6551 conn.handleResponse(o, trans);
6554 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
6556 if(this.autoAbort !== false){
6560 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
6562 var script = document.createElement("script");
6563 script.setAttribute("src", url);
6564 script.setAttribute("type", "text/javascript");
6565 script.setAttribute("id", trans.scriptId);
6566 this.head.appendChild(script);
6570 callback.call(scope||this, null, arg, false);
6575 isLoading : function(){
6576 return this.trans ? true : false;
6580 * Abort the current server request.
6583 if(this.isLoading()){
6584 this.destroyTrans(this.trans);
6589 destroyTrans : function(trans, isLoaded){
6590 this.head.removeChild(document.getElementById(trans.scriptId));
6591 clearTimeout(trans.timeoutId);
6593 window[trans.cb] = undefined;
6595 delete window[trans.cb];
6598 // if hasn't been loaded, wait for load to remove it to prevent script error
6599 window[trans.cb] = function(){
6600 window[trans.cb] = undefined;
6602 delete window[trans.cb];
6609 handleResponse : function(o, trans){
6611 this.destroyTrans(trans, true);
6614 result = trans.reader.readRecords(o);
6616 this.fireEvent("loadexception", this, o, trans.arg, e);
6617 trans.callback.call(trans.scope||window, null, trans.arg, false);
6620 this.fireEvent("load", this, o, trans.arg);
6621 trans.callback.call(trans.scope||window, result, trans.arg, true);
6625 handleFailure : function(trans){
6627 this.destroyTrans(trans, false);
6628 this.fireEvent("loadexception", this, null, trans.arg);
6629 trans.callback.call(trans.scope||window, null, trans.arg, false);
6633 * Ext JS Library 1.1.1
6634 * Copyright(c) 2006-2007, Ext JS, LLC.
6636 * Originally Released Under LGPL - original licence link has changed is not relivant.
6639 * <script type="text/javascript">
6643 * @class Roo.data.JsonReader
6644 * @extends Roo.data.DataReader
6645 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6646 * based on mappings in a provided Roo.data.Record constructor.
6648 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6649 * in the reply previously.
6654 var RecordDef = Roo.data.Record.create([
6655 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6656 {name: 'occupation'} // This field will use "occupation" as the mapping.
6658 var myReader = new Roo.data.JsonReader({
6659 totalProperty: "results", // The property which contains the total dataset size (optional)
6660 root: "rows", // The property which contains an Array of row objects
6661 id: "id" // The property within each row object that provides an ID for the record (optional)
6665 * This would consume a JSON file like this:
6667 { 'results': 2, 'rows': [
6668 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6669 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6672 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6673 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6674 * paged from the remote server.
6675 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6676 * @cfg {String} root name of the property which contains the Array of row objects.
6677 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6679 * Create a new JsonReader
6680 * @param {Object} meta Metadata configuration options
6681 * @param {Object} recordType Either an Array of field definition objects,
6682 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6684 Roo.data.JsonReader = function(meta, recordType){
6687 // set some defaults:
6689 totalProperty: 'total',
6690 successProperty : 'success',
6695 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6697 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6700 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6701 * Used by Store query builder to append _requestMeta to params.
6704 metaFromRemote : false,
6706 * This method is only used by a DataProxy which has retrieved data from a remote server.
6707 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6708 * @return {Object} data A data block which is used by an Roo.data.Store object as
6709 * a cache of Roo.data.Records.
6711 read : function(response){
6712 var json = response.responseText;
6714 var o = /* eval:var:o */ eval("("+json+")");
6716 throw {message: "JsonReader.read: Json object not found"};
6722 this.metaFromRemote = true;
6723 this.meta = o.metaData;
6724 this.recordType = Roo.data.Record.create(o.metaData.fields);
6725 this.onMetaChange(this.meta, this.recordType, o);
6727 return this.readRecords(o);
6730 // private function a store will implement
6731 onMetaChange : function(meta, recordType, o){
6738 simpleAccess: function(obj, subsc) {
6745 getJsonAccessor: function(){
6747 return function(expr) {
6749 return(re.test(expr))
6750 ? new Function("obj", "return obj." + expr)
6760 * Create a data block containing Roo.data.Records from an XML document.
6761 * @param {Object} o An object which contains an Array of row objects in the property specified
6762 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6763 * which contains the total size of the dataset.
6764 * @return {Object} data A data block which is used by an Roo.data.Store object as
6765 * a cache of Roo.data.Records.
6767 readRecords : function(o){
6769 * After any data loads, the raw JSON data is available for further custom processing.
6773 var s = this.meta, Record = this.recordType,
6774 f = Record.prototype.fields, fi = f.items, fl = f.length;
6776 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6778 if(s.totalProperty) {
6779 this.getTotal = this.getJsonAccessor(s.totalProperty);
6781 if(s.successProperty) {
6782 this.getSuccess = this.getJsonAccessor(s.successProperty);
6784 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6786 var g = this.getJsonAccessor(s.id);
6787 this.getId = function(rec) {
6789 return (r === undefined || r === "") ? null : r;
6792 this.getId = function(){return null;};
6795 for(var jj = 0; jj < fl; jj++){
6797 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6798 this.ef[jj] = this.getJsonAccessor(map);
6802 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6803 if(s.totalProperty){
6804 var vt = parseInt(this.getTotal(o), 10);
6809 if(s.successProperty){
6810 var vs = this.getSuccess(o);
6811 if(vs === false || vs === 'false'){
6816 for(var i = 0; i < c; i++){
6819 var id = this.getId(n);
6820 for(var j = 0; j < fl; j++){
6822 var v = this.ef[j](n);
6824 Roo.log('missing convert for ' + f.name);
6828 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6830 var record = new Record(values, id);
6832 records[i] = record;
6838 totalRecords : totalRecords
6843 * Ext JS Library 1.1.1
6844 * Copyright(c) 2006-2007, Ext JS, LLC.
6846 * Originally Released Under LGPL - original licence link has changed is not relivant.
6849 * <script type="text/javascript">
6853 * @class Roo.data.ArrayReader
6854 * @extends Roo.data.DataReader
6855 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6856 * Each element of that Array represents a row of data fields. The
6857 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6858 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6862 var RecordDef = Roo.data.Record.create([
6863 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6864 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6866 var myReader = new Roo.data.ArrayReader({
6867 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6871 * This would consume an Array like this:
6873 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6875 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6877 * Create a new JsonReader
6878 * @param {Object} meta Metadata configuration options.
6879 * @param {Object} recordType Either an Array of field definition objects
6880 * as specified to {@link Roo.data.Record#create},
6881 * or an {@link Roo.data.Record} object
6882 * created using {@link Roo.data.Record#create}.
6884 Roo.data.ArrayReader = function(meta, recordType){
6885 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6888 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6890 * Create a data block containing Roo.data.Records from an XML document.
6891 * @param {Object} o An Array of row objects which represents the dataset.
6892 * @return {Object} data A data block which is used by an Roo.data.Store object as
6893 * a cache of Roo.data.Records.
6895 readRecords : function(o){
6896 var sid = this.meta ? this.meta.id : null;
6897 var recordType = this.recordType, fields = recordType.prototype.fields;
6900 for(var i = 0; i < root.length; i++){
6903 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6904 for(var j = 0, jlen = fields.length; j < jlen; j++){
6905 var f = fields.items[j];
6906 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6907 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6911 var record = new recordType(values, id);
6913 records[records.length] = record;
6917 totalRecords : records.length
6926 * @class Roo.bootstrap.ComboBox
6927 * @extends Roo.bootstrap.TriggerField
6928 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
6930 * Create a new ComboBox.
6931 * @param {Object} config Configuration options
6933 Roo.bootstrap.ComboBox = function(config){
6934 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
6938 * Fires when the dropdown list is expanded
6939 * @param {Roo.bootstrap.ComboBox} combo This combo box
6944 * Fires when the dropdown list is collapsed
6945 * @param {Roo.bootstrap.ComboBox} combo This combo box
6949 * @event beforeselect
6950 * Fires before a list item is selected. Return false to cancel the selection.
6951 * @param {Roo.bootstrap.ComboBox} combo This combo box
6952 * @param {Roo.data.Record} record The data record returned from the underlying store
6953 * @param {Number} index The index of the selected item in the dropdown list
6955 'beforeselect' : true,
6958 * Fires when a list item is selected
6959 * @param {Roo.bootstrap.ComboBox} combo This combo box
6960 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
6961 * @param {Number} index The index of the selected item in the dropdown list
6965 * @event beforequery
6966 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
6967 * The event object passed has these properties:
6968 * @param {Roo.bootstrap.ComboBox} combo This combo box
6969 * @param {String} query The query
6970 * @param {Boolean} forceAll true to force "all" query
6971 * @param {Boolean} cancel true to cancel the query
6972 * @param {Object} e The query event object
6974 'beforequery': true,
6977 * Fires when the 'add' icon is pressed (add a listener to enable add button)
6978 * @param {Roo.bootstrap.ComboBox} combo This combo box
6983 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
6984 * @param {Roo.bootstrap.ComboBox} combo This combo box
6985 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
6993 this.selectedIndex = -1;
6994 if(this.mode == 'local'){
6995 if(config.queryDelay === undefined){
6996 this.queryDelay = 10;
6998 if(config.minChars === undefined){
7004 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
7007 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
7008 * rendering into an Roo.Editor, defaults to false)
7011 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
7012 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
7015 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
7018 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
7019 * the dropdown list (defaults to undefined, with no header element)
7023 * @cfg {String/Roo.Template} tpl The template to use to render the output
7027 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
7029 listWidth: undefined,
7031 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
7032 * mode = 'remote' or 'text' if mode = 'local')
7034 displayField: undefined,
7036 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
7037 * mode = 'remote' or 'value' if mode = 'local').
7038 * Note: use of a valueField requires the user make a selection
7039 * in order for a value to be mapped.
7041 valueField: undefined,
7045 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
7046 * field's data value (defaults to the underlying DOM element's name)
7048 hiddenName: undefined,
7050 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
7054 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
7056 selectedClass: 'active',
7059 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
7063 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
7064 * anchor positions (defaults to 'tl-bl')
7066 listAlign: 'tl-bl?',
7068 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
7072 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
7073 * query specified by the allQuery config option (defaults to 'query')
7075 triggerAction: 'query',
7077 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
7078 * (defaults to 4, does not apply if editable = false)
7082 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
7083 * delay (typeAheadDelay) if it matches a known value (defaults to false)
7087 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
7088 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
7092 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
7093 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
7097 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
7098 * when editable = true (defaults to false)
7100 selectOnFocus:false,
7102 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
7104 queryParam: 'query',
7106 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
7107 * when mode = 'remote' (defaults to 'Loading...')
7109 loadingText: 'Loading...',
7111 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
7115 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
7119 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
7120 * traditional select (defaults to true)
7124 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
7128 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
7132 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
7133 * listWidth has a higher value)
7137 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
7138 * allow the user to set arbitrary text into the field (defaults to false)
7140 forceSelection:false,
7142 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
7143 * if typeAhead = true (defaults to 250)
7145 typeAheadDelay : 250,
7147 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
7148 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
7150 valueNotFoundText : undefined,
7152 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
7157 * @cfg {Boolean} disableClear Disable showing of clear button.
7159 disableClear : false,
7161 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
7163 alwaysQuery : false,
7169 // element that contains real text value.. (when hidden is used..)
7172 initEvents: function(){
7175 throw "can not find store for combo";
7177 this.store = Roo.factory(this.store, Roo.data);
7181 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
7184 if(this.hiddenName){
7186 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
7188 this.hiddenField.dom.value =
7189 this.hiddenValue !== undefined ? this.hiddenValue :
7190 this.value !== undefined ? this.value : '';
7192 // prevent input submission
7193 this.el.dom.removeAttribute('name');
7194 this.hiddenField.dom.setAttribute('name', this.hiddenName);
7199 // this.el.dom.setAttribute('autocomplete', 'off');
7202 var cls = 'x-combo-list';
7203 this.list = this.el.select('ul',true).first();
7205 //this.list = new Roo.Layer({
7206 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
7209 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
7210 this.list.setWidth(lw);
7212 this.list.on('mouseover', this.onViewOver, this);
7213 this.list.on('mousemove', this.onViewMove, this);
7216 this.list.swallowEvent('mousewheel');
7217 this.assetHeight = 0;
7220 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
7221 this.assetHeight += this.header.getHeight();
7224 this.innerList = this.list.createChild({cls:cls+'-inner'});
7225 this.innerList.on('mouseover', this.onViewOver, this);
7226 this.innerList.on('mousemove', this.onViewMove, this);
7227 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7229 if(this.allowBlank && !this.pageSize && !this.disableClear){
7230 this.footer = this.list.createChild({cls:cls+'-ft'});
7231 this.pageTb = new Roo.Toolbar(this.footer);
7235 this.footer = this.list.createChild({cls:cls+'-ft'});
7236 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
7237 {pageSize: this.pageSize});
7241 if (this.pageTb && this.allowBlank && !this.disableClear) {
7243 this.pageTb.add(new Roo.Toolbar.Fill(), {
7244 cls: 'x-btn-icon x-btn-clear',
7250 _this.onSelect(false, -1);
7255 this.assetHeight += this.footer.getHeight();
7260 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
7263 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
7264 singleSelect:true, store: this.store, selectedClass: this.selectedClass
7266 //this.view.wrapEl.setDisplayed(false);
7267 this.view.on('click', this.onViewClick, this);
7271 this.store.on('beforeload', this.onBeforeLoad, this);
7272 this.store.on('load', this.onLoad, this);
7273 this.store.on('loadexception', this.onLoadException, this);
7276 this.resizer = new Roo.Resizable(this.list, {
7277 pinned:true, handles:'se'
7279 this.resizer.on('resize', function(r, w, h){
7280 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
7282 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
7283 this.restrictHeight();
7285 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
7289 this.editable = true;
7290 this.setEditable(false);
7295 if (typeof(this.events.add.listeners) != 'undefined') {
7297 this.addicon = this.wrap.createChild(
7298 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
7300 this.addicon.on('click', function(e) {
7301 this.fireEvent('add', this);
7304 if (typeof(this.events.edit.listeners) != 'undefined') {
7306 this.editicon = this.wrap.createChild(
7307 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
7309 this.editicon.setStyle('margin-left', '40px');
7311 this.editicon.on('click', function(e) {
7313 // we fire even if inothing is selected..
7314 this.fireEvent('edit', this, this.lastData );
7321 this.keyNav = new Roo.KeyNav(this.inputEl(), {
7323 this.inKeyMode = true;
7327 "down" : function(e){
7328 if(!this.isExpanded()){
7329 this.onTriggerClick();
7331 this.inKeyMode = true;
7336 "enter" : function(e){
7341 "esc" : function(e){
7345 "tab" : function(e){
7348 if(this.fireEvent("specialkey", this, e)){
7349 this.onViewClick(false);
7357 doRelay : function(foo, bar, hname){
7358 if(hname == 'down' || this.scope.isExpanded()){
7359 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
7368 this.queryDelay = Math.max(this.queryDelay || 10,
7369 this.mode == 'local' ? 10 : 250);
7372 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
7375 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
7377 if(this.editable !== false){
7378 this.inputEl().on("keyup", this.onKeyUp, this);
7380 if(this.forceSelection){
7381 this.on('blur', this.doForce, this);
7385 onDestroy : function(){
7387 this.view.setStore(null);
7388 this.view.el.removeAllListeners();
7389 this.view.el.remove();
7390 this.view.purgeListeners();
7393 this.list.dom.innerHTML = '';
7396 this.store.un('beforeload', this.onBeforeLoad, this);
7397 this.store.un('load', this.onLoad, this);
7398 this.store.un('loadexception', this.onLoadException, this);
7400 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
7404 fireKey : function(e){
7405 if(e.isNavKeyPress() && !this.list.isVisible()){
7406 this.fireEvent("specialkey", this, e);
7411 onResize: function(w, h){
7412 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
7414 // if(typeof w != 'number'){
7415 // // we do not handle it!?!?
7418 // var tw = this.trigger.getWidth();
7419 // // tw += this.addicon ? this.addicon.getWidth() : 0;
7420 // // tw += this.editicon ? this.editicon.getWidth() : 0;
7422 // this.inputEl().setWidth( this.adjustWidth('input', x));
7424 // //this.trigger.setStyle('left', x+'px');
7426 // if(this.list && this.listWidth === undefined){
7427 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
7428 // this.list.setWidth(lw);
7429 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7437 * Allow or prevent the user from directly editing the field text. If false is passed,
7438 * the user will only be able to select from the items defined in the dropdown list. This method
7439 * is the runtime equivalent of setting the 'editable' config option at config time.
7440 * @param {Boolean} value True to allow the user to directly edit the field text
7442 setEditable : function(value){
7443 if(value == this.editable){
7446 this.editable = value;
7448 this.inputEl().dom.setAttribute('readOnly', true);
7449 this.inputEl().on('mousedown', this.onTriggerClick, this);
7450 this.inputEl().addClass('x-combo-noedit');
7452 this.inputEl().dom.setAttribute('readOnly', false);
7453 this.inputEl().un('mousedown', this.onTriggerClick, this);
7454 this.inputEl().removeClass('x-combo-noedit');
7459 onBeforeLoad : function(){
7463 //this.innerList.update(this.loadingText ?
7464 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
7465 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
7467 this.restrictHeight();
7468 this.selectedIndex = -1;
7472 onLoad : function(){
7476 if(this.store.getCount() > 0){
7478 this.restrictHeight();
7479 if(this.lastQuery == this.allQuery){
7481 this.inputEl().dom.select();
7483 if(!this.selectByValue(this.value, true)){
7484 this.select(0, true);
7488 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
7489 this.taTask.delay(this.typeAheadDelay);
7493 this.onEmptyResults();
7498 onLoadException : function()
7501 Roo.log(this.store.reader.jsonData);
7502 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7504 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7510 onTypeAhead : function(){
7511 if(this.store.getCount() > 0){
7512 var r = this.store.getAt(0);
7513 var newValue = r.data[this.displayField];
7514 var len = newValue.length;
7515 var selStart = this.getRawValue().length;
7517 if(selStart != len){
7518 this.setRawValue(newValue);
7519 this.selectText(selStart, newValue.length);
7525 onSelect : function(record, index){
7526 if(this.fireEvent('beforeselect', this, record, index) !== false){
7527 this.setFromData(index > -1 ? record.data : false);
7529 this.fireEvent('select', this, record, index);
7534 * Returns the currently selected field value or empty string if no value is set.
7535 * @return {String} value The selected value
7537 getValue : function(){
7538 if(this.valueField){
7539 return typeof this.value != 'undefined' ? this.value : '';
7541 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
7546 * Clears any text/value currently set in the field
7548 clearValue : function(){
7549 if(this.hiddenField){
7550 this.hiddenField.dom.value = '';
7553 this.setRawValue('');
7554 this.lastSelectionText = '';
7559 * Sets the specified value into the field. If the value finds a match, the corresponding record text
7560 * will be displayed in the field. If the value does not match the data value of an existing item,
7561 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
7562 * Otherwise the field will be blank (although the value will still be set).
7563 * @param {String} value The value to match
7565 setValue : function(v){
7567 if(this.valueField){
7568 var r = this.findRecord(this.valueField, v);
7570 text = r.data[this.displayField];
7571 }else if(this.valueNotFoundText !== undefined){
7572 text = this.valueNotFoundText;
7575 this.lastSelectionText = text;
7576 if(this.hiddenField){
7577 this.hiddenField.dom.value = v;
7579 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
7583 * @property {Object} the last set data for the element
7588 * Sets the value of the field based on a object which is related to the record format for the store.
7589 * @param {Object} value the value to set as. or false on reset?
7591 setFromData : function(o){
7592 var dv = ''; // display value
7593 var vv = ''; // value value..
7595 if (this.displayField) {
7596 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
7598 // this is an error condition!!!
7599 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
7602 if(this.valueField){
7603 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
7605 if(this.hiddenField){
7606 this.hiddenField.dom.value = vv;
7608 this.lastSelectionText = dv;
7609 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7613 // no hidden field.. - we store the value in 'value', but still display
7614 // display field!!!!
7615 this.lastSelectionText = dv;
7616 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7623 // overridden so that last data is reset..
7624 this.setValue(this.originalValue);
7625 this.clearInvalid();
7626 this.lastData = false;
7628 this.view.clearSelections();
7632 findRecord : function(prop, value){
7634 if(this.store.getCount() > 0){
7635 this.store.each(function(r){
7636 if(r.data[prop] == value){
7648 // returns hidden if it's set..
7649 if (!this.rendered) {return ''};
7650 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
7654 onViewMove : function(e, t){
7655 this.inKeyMode = false;
7659 onViewOver : function(e, t){
7660 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
7663 var item = this.view.findItemFromChild(t);
7665 var index = this.view.indexOf(item);
7666 this.select(index, false);
7671 onViewClick : function(doFocus)
7673 var index = this.view.getSelectedIndexes()[0];
7674 var r = this.store.getAt(index);
7676 this.onSelect(r, index);
7678 if(doFocus !== false && !this.blockFocus){
7679 this.inputEl().focus();
7684 restrictHeight : function(){
7685 //this.innerList.dom.style.height = '';
7686 //var inner = this.innerList.dom;
7687 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
7688 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
7689 //this.list.beginUpdate();
7690 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
7691 this.list.alignTo(this.inputEl(), this.listAlign);
7692 //this.list.endUpdate();
7696 onEmptyResults : function(){
7701 * Returns true if the dropdown list is expanded, else false.
7703 isExpanded : function(){
7704 return this.list.isVisible();
7708 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
7709 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7710 * @param {String} value The data value of the item to select
7711 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7712 * selected item if it is not currently in view (defaults to true)
7713 * @return {Boolean} True if the value matched an item in the list, else false
7715 selectByValue : function(v, scrollIntoView){
7716 if(v !== undefined && v !== null){
7717 var r = this.findRecord(this.valueField || this.displayField, v);
7719 this.select(this.store.indexOf(r), scrollIntoView);
7727 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
7728 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7729 * @param {Number} index The zero-based index of the list item to select
7730 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7731 * selected item if it is not currently in view (defaults to true)
7733 select : function(index, scrollIntoView){
7734 this.selectedIndex = index;
7735 this.view.select(index);
7736 if(scrollIntoView !== false){
7737 var el = this.view.getNode(index);
7739 //this.innerList.scrollChildIntoView(el, false);
7746 selectNext : function(){
7747 var ct = this.store.getCount();
7749 if(this.selectedIndex == -1){
7751 }else if(this.selectedIndex < ct-1){
7752 this.select(this.selectedIndex+1);
7758 selectPrev : function(){
7759 var ct = this.store.getCount();
7761 if(this.selectedIndex == -1){
7763 }else if(this.selectedIndex != 0){
7764 this.select(this.selectedIndex-1);
7770 onKeyUp : function(e){
7771 if(this.editable !== false && !e.isSpecialKey()){
7772 this.lastKey = e.getKey();
7773 this.dqTask.delay(this.queryDelay);
7778 validateBlur : function(){
7779 return !this.list || !this.list.isVisible();
7783 initQuery : function(){
7784 this.doQuery(this.getRawValue());
7788 doForce : function(){
7789 if(this.el.dom.value.length > 0){
7791 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
7797 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
7798 * query allowing the query action to be canceled if needed.
7799 * @param {String} query The SQL query to execute
7800 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
7801 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
7802 * saved in the current store (defaults to false)
7804 doQuery : function(q, forceAll){
7805 if(q === undefined || q === null){
7814 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
7818 forceAll = qe.forceAll;
7819 if(forceAll === true || (q.length >= this.minChars)){
7820 if(this.lastQuery != q || this.alwaysQuery){
7822 if(this.mode == 'local'){
7823 this.selectedIndex = -1;
7825 this.store.clearFilter();
7827 this.store.filter(this.displayField, q);
7831 this.store.baseParams[this.queryParam] = q;
7833 params: this.getParams(q)
7838 this.selectedIndex = -1;
7845 getParams : function(q){
7847 //p[this.queryParam] = q;
7850 p.limit = this.pageSize;
7856 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
7858 collapse : function(){
7859 if(!this.isExpanded()){
7863 Roo.get(document).un('mousedown', this.collapseIf, this);
7864 Roo.get(document).un('mousewheel', this.collapseIf, this);
7865 if (!this.editable) {
7866 Roo.get(document).un('keydown', this.listKeyPress, this);
7868 this.fireEvent('collapse', this);
7872 collapseIf : function(e){
7873 if(!e.within(this.el) && !e.within(this.el)){
7879 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
7881 expand : function(){
7883 if(this.isExpanded() || !this.hasFocus){
7886 this.list.alignTo(this.inputEl(), this.listAlign);
7888 Roo.get(document).on('mousedown', this.collapseIf, this);
7889 Roo.get(document).on('mousewheel', this.collapseIf, this);
7890 if (!this.editable) {
7891 Roo.get(document).on('keydown', this.listKeyPress, this);
7894 this.fireEvent('expand', this);
7898 // Implements the default empty TriggerField.onTriggerClick function
7899 onTriggerClick : function()
7901 Roo.log('trigger click');
7906 if(this.isExpanded()){
7908 if (!this.blockFocus) {
7909 this.inputEl().focus();
7913 this.hasFocus = true;
7914 if(this.triggerAction == 'all') {
7915 this.doQuery(this.allQuery, true);
7917 this.doQuery(this.getRawValue());
7919 if (!this.blockFocus) {
7920 this.inputEl().focus();
7924 listKeyPress : function(e)
7926 //Roo.log('listkeypress');
7927 // scroll to first matching element based on key pres..
7928 if (e.isSpecialKey()) {
7931 var k = String.fromCharCode(e.getKey()).toUpperCase();
7934 var csel = this.view.getSelectedNodes();
7935 var cselitem = false;
7937 var ix = this.view.indexOf(csel[0]);
7938 cselitem = this.store.getAt(ix);
7939 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
7945 this.store.each(function(v) {
7947 // start at existing selection.
7948 if (cselitem.id == v.id) {
7954 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
7955 match = this.store.indexOf(v);
7961 if (match === false) {
7962 return true; // no more action?
7965 this.view.select(match);
7966 var sn = Roo.get(this.view.getSelectedNodes()[0])
7967 //sn.scrollIntoView(sn.dom.parentNode, false);
7971 * @cfg {Boolean} grow
7975 * @cfg {Number} growMin
7979 * @cfg {Number} growMax
7988 * Ext JS Library 1.1.1
7989 * Copyright(c) 2006-2007, Ext JS, LLC.
7991 * Originally Released Under LGPL - original licence link has changed is not relivant.
7994 * <script type="text/javascript">
7999 * @extends Roo.util.Observable
8000 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
8001 * This class also supports single and multi selection modes. <br>
8002 * Create a data model bound view:
8004 var store = new Roo.data.Store(...);
8006 var view = new Roo.View({
8008 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
8011 selectedClass: "ydataview-selected",
8015 // listen for node click?
8016 view.on("click", function(vw, index, node, e){
8017 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
8021 dataModel.load("foobar.xml");
8023 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
8025 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
8026 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
8028 * Note: old style constructor is still suported (container, template, config)
8032 * @param {Object} config The config object
8035 Roo.View = function(config, depreciated_tpl, depreciated_config){
8037 if (typeof(depreciated_tpl) == 'undefined') {
8038 // new way.. - universal constructor.
8039 Roo.apply(this, config);
8040 this.el = Roo.get(this.el);
8043 this.el = Roo.get(config);
8044 this.tpl = depreciated_tpl;
8045 Roo.apply(this, depreciated_config);
8047 this.wrapEl = this.el.wrap().wrap();
8048 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
8051 if(typeof(this.tpl) == "string"){
8052 this.tpl = new Roo.Template(this.tpl);
8054 // support xtype ctors..
8055 this.tpl = new Roo.factory(this.tpl, Roo);
8067 * @event beforeclick
8068 * Fires before a click is processed. Returns false to cancel the default action.
8069 * @param {Roo.View} this
8070 * @param {Number} index The index of the target node
8071 * @param {HTMLElement} node The target node
8072 * @param {Roo.EventObject} e The raw event object
8074 "beforeclick" : true,
8077 * Fires when a template node is clicked.
8078 * @param {Roo.View} this
8079 * @param {Number} index The index of the target node
8080 * @param {HTMLElement} node The target node
8081 * @param {Roo.EventObject} e The raw event object
8086 * Fires when a template node is double clicked.
8087 * @param {Roo.View} this
8088 * @param {Number} index The index of the target node
8089 * @param {HTMLElement} node The target node
8090 * @param {Roo.EventObject} e The raw event object
8094 * @event contextmenu
8095 * Fires when a template node is right clicked.
8096 * @param {Roo.View} this
8097 * @param {Number} index The index of the target node
8098 * @param {HTMLElement} node The target node
8099 * @param {Roo.EventObject} e The raw event object
8101 "contextmenu" : true,
8103 * @event selectionchange
8104 * Fires when the selected nodes change.
8105 * @param {Roo.View} this
8106 * @param {Array} selections Array of the selected nodes
8108 "selectionchange" : true,
8111 * @event beforeselect
8112 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
8113 * @param {Roo.View} this
8114 * @param {HTMLElement} node The node to be selected
8115 * @param {Array} selections Array of currently selected nodes
8117 "beforeselect" : true,
8119 * @event preparedata
8120 * Fires on every row to render, to allow you to change the data.
8121 * @param {Roo.View} this
8122 * @param {Object} data to be rendered (change this)
8124 "preparedata" : true
8132 "click": this.onClick,
8133 "dblclick": this.onDblClick,
8134 "contextmenu": this.onContextMenu,
8138 this.selections = [];
8140 this.cmp = new Roo.CompositeElementLite([]);
8142 this.store = Roo.factory(this.store, Roo.data);
8143 this.setStore(this.store, true);
8146 if ( this.footer && this.footer.xtype) {
8148 var fctr = this.wrapEl.appendChild(document.createElement("div"));
8150 this.footer.dataSource = this.store
8151 this.footer.container = fctr;
8152 this.footer = Roo.factory(this.footer, Roo);
8153 fctr.insertFirst(this.el);
8155 // this is a bit insane - as the paging toolbar seems to detach the el..
8156 // dom.parentNode.parentNode.parentNode
8157 // they get detached?
8161 Roo.View.superclass.constructor.call(this);
8166 Roo.extend(Roo.View, Roo.util.Observable, {
8169 * @cfg {Roo.data.Store} store Data store to load data from.
8174 * @cfg {String|Roo.Element} el The container element.
8179 * @cfg {String|Roo.Template} tpl The template used by this View
8183 * @cfg {String} dataName the named area of the template to use as the data area
8184 * Works with domtemplates roo-name="name"
8188 * @cfg {String} selectedClass The css class to add to selected nodes
8190 selectedClass : "x-view-selected",
8192 * @cfg {String} emptyText The empty text to show when nothing is loaded.
8197 * @cfg {String} text to display on mask (default Loading)
8201 * @cfg {Boolean} multiSelect Allow multiple selection
8203 multiSelect : false,
8205 * @cfg {Boolean} singleSelect Allow single selection
8207 singleSelect: false,
8210 * @cfg {Boolean} toggleSelect - selecting
8212 toggleSelect : false,
8215 * Returns the element this view is bound to.
8216 * @return {Roo.Element}
8225 * Refreshes the view. - called by datachanged on the store. - do not call directly.
8227 refresh : function(){
8230 // if we are using something like 'domtemplate', then
8231 // the what gets used is:
8232 // t.applySubtemplate(NAME, data, wrapping data..)
8233 // the outer template then get' applied with
8234 // the store 'extra data'
8235 // and the body get's added to the
8236 // roo-name="data" node?
8237 // <span class='roo-tpl-{name}'></span> ?????
8241 this.clearSelections();
8244 var records = this.store.getRange();
8245 if(records.length < 1) {
8247 // is this valid?? = should it render a template??
8249 this.el.update(this.emptyText);
8253 if (this.dataName) {
8254 this.el.update(t.apply(this.store.meta)); //????
8255 el = this.el.child('.roo-tpl-' + this.dataName);
8258 for(var i = 0, len = records.length; i < len; i++){
8259 var data = this.prepareData(records[i].data, i, records[i]);
8260 this.fireEvent("preparedata", this, data, i, records[i]);
8261 html[html.length] = Roo.util.Format.trim(
8263 t.applySubtemplate(this.dataName, data, this.store.meta) :
8270 el.update(html.join(""));
8271 this.nodes = el.dom.childNodes;
8272 this.updateIndexes(0);
8276 * Function to override to reformat the data that is sent to
8277 * the template for each node.
8278 * DEPRICATED - use the preparedata event handler.
8279 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
8280 * a JSON object for an UpdateManager bound view).
8282 prepareData : function(data, index, record)
8284 this.fireEvent("preparedata", this, data, index, record);
8288 onUpdate : function(ds, record){
8289 this.clearSelections();
8290 var index = this.store.indexOf(record);
8291 var n = this.nodes[index];
8292 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
8293 n.parentNode.removeChild(n);
8294 this.updateIndexes(index, index);
8300 onAdd : function(ds, records, index)
8302 this.clearSelections();
8303 if(this.nodes.length == 0){
8307 var n = this.nodes[index];
8308 for(var i = 0, len = records.length; i < len; i++){
8309 var d = this.prepareData(records[i].data, i, records[i]);
8311 this.tpl.insertBefore(n, d);
8314 this.tpl.append(this.el, d);
8317 this.updateIndexes(index);
8320 onRemove : function(ds, record, index){
8321 this.clearSelections();
8322 var el = this.dataName ?
8323 this.el.child('.roo-tpl-' + this.dataName) :
8325 el.dom.removeChild(this.nodes[index]);
8326 this.updateIndexes(index);
8330 * Refresh an individual node.
8331 * @param {Number} index
8333 refreshNode : function(index){
8334 this.onUpdate(this.store, this.store.getAt(index));
8337 updateIndexes : function(startIndex, endIndex){
8338 var ns = this.nodes;
8339 startIndex = startIndex || 0;
8340 endIndex = endIndex || ns.length - 1;
8341 for(var i = startIndex; i <= endIndex; i++){
8342 ns[i].nodeIndex = i;
8347 * Changes the data store this view uses and refresh the view.
8348 * @param {Store} store
8350 setStore : function(store, initial){
8351 if(!initial && this.store){
8352 this.store.un("datachanged", this.refresh);
8353 this.store.un("add", this.onAdd);
8354 this.store.un("remove", this.onRemove);
8355 this.store.un("update", this.onUpdate);
8356 this.store.un("clear", this.refresh);
8357 this.store.un("beforeload", this.onBeforeLoad);
8358 this.store.un("load", this.onLoad);
8359 this.store.un("loadexception", this.onLoad);
8363 store.on("datachanged", this.refresh, this);
8364 store.on("add", this.onAdd, this);
8365 store.on("remove", this.onRemove, this);
8366 store.on("update", this.onUpdate, this);
8367 store.on("clear", this.refresh, this);
8368 store.on("beforeload", this.onBeforeLoad, this);
8369 store.on("load", this.onLoad, this);
8370 store.on("loadexception", this.onLoad, this);
8378 * onbeforeLoad - masks the loading area.
8381 onBeforeLoad : function()
8384 this.el.mask(this.mask ? this.mask : "Loading" );
8386 onLoad : function ()
8393 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
8394 * @param {HTMLElement} node
8395 * @return {HTMLElement} The template node
8397 findItemFromChild : function(node){
8398 var el = this.dataName ?
8399 this.el.child('.roo-tpl-' + this.dataName,true) :
8402 if(!node || node.parentNode == el){
8405 var p = node.parentNode;
8406 while(p && p != el){
8407 if(p.parentNode == el){
8416 onClick : function(e){
8417 var item = this.findItemFromChild(e.getTarget());
8419 var index = this.indexOf(item);
8420 if(this.onItemClick(item, index, e) !== false){
8421 this.fireEvent("click", this, index, item, e);
8424 this.clearSelections();
8429 onContextMenu : function(e){
8430 var item = this.findItemFromChild(e.getTarget());
8432 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
8437 onDblClick : function(e){
8438 var item = this.findItemFromChild(e.getTarget());
8440 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
8444 onItemClick : function(item, index, e)
8446 if(this.fireEvent("beforeclick", this, index, item, e) === false){
8449 if (this.toggleSelect) {
8450 var m = this.isSelected(item) ? 'unselect' : 'select';
8453 _t[m](item, true, false);
8456 if(this.multiSelect || this.singleSelect){
8457 if(this.multiSelect && e.shiftKey && this.lastSelection){
8458 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
8460 this.select(item, this.multiSelect && e.ctrlKey);
8461 this.lastSelection = item;
8469 * Get the number of selected nodes.
8472 getSelectionCount : function(){
8473 return this.selections.length;
8477 * Get the currently selected nodes.
8478 * @return {Array} An array of HTMLElements
8480 getSelectedNodes : function(){
8481 return this.selections;
8485 * Get the indexes of the selected nodes.
8488 getSelectedIndexes : function(){
8489 var indexes = [], s = this.selections;
8490 for(var i = 0, len = s.length; i < len; i++){
8491 indexes.push(s[i].nodeIndex);
8497 * Clear all selections
8498 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
8500 clearSelections : function(suppressEvent){
8501 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
8502 this.cmp.elements = this.selections;
8503 this.cmp.removeClass(this.selectedClass);
8504 this.selections = [];
8506 this.fireEvent("selectionchange", this, this.selections);
8512 * Returns true if the passed node is selected
8513 * @param {HTMLElement/Number} node The node or node index
8516 isSelected : function(node){
8517 var s = this.selections;
8521 node = this.getNode(node);
8522 return s.indexOf(node) !== -1;
8527 * @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
8528 * @param {Boolean} keepExisting (optional) true to keep existing selections
8529 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8531 select : function(nodeInfo, keepExisting, suppressEvent){
8532 if(nodeInfo instanceof Array){
8534 this.clearSelections(true);
8536 for(var i = 0, len = nodeInfo.length; i < len; i++){
8537 this.select(nodeInfo[i], true, true);
8541 var node = this.getNode(nodeInfo);
8542 if(!node || this.isSelected(node)){
8543 return; // already selected.
8546 this.clearSelections(true);
8548 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
8549 Roo.fly(node).addClass(this.selectedClass);
8550 this.selections.push(node);
8552 this.fireEvent("selectionchange", this, this.selections);
8560 * @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
8561 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
8562 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8564 unselect : function(nodeInfo, keepExisting, suppressEvent)
8566 if(nodeInfo instanceof Array){
8567 Roo.each(this.selections, function(s) {
8568 this.unselect(s, nodeInfo);
8572 var node = this.getNode(nodeInfo);
8573 if(!node || !this.isSelected(node)){
8574 Roo.log("not selected");
8575 return; // not selected.
8579 Roo.each(this.selections, function(s) {
8581 Roo.fly(node).removeClass(this.selectedClass);
8588 this.selections= ns;
8589 this.fireEvent("selectionchange", this, this.selections);
8593 * Gets a template node.
8594 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8595 * @return {HTMLElement} The node or null if it wasn't found
8597 getNode : function(nodeInfo){
8598 if(typeof nodeInfo == "string"){
8599 return document.getElementById(nodeInfo);
8600 }else if(typeof nodeInfo == "number"){
8601 return this.nodes[nodeInfo];
8607 * Gets a range template nodes.
8608 * @param {Number} startIndex
8609 * @param {Number} endIndex
8610 * @return {Array} An array of nodes
8612 getNodes : function(start, end){
8613 var ns = this.nodes;
8615 end = typeof end == "undefined" ? ns.length - 1 : end;
8618 for(var i = start; i <= end; i++){
8622 for(var i = start; i >= end; i--){
8630 * Finds the index of the passed node
8631 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8632 * @return {Number} The index of the node or -1
8634 indexOf : function(node){
8635 node = this.getNode(node);
8636 if(typeof node.nodeIndex == "number"){
8637 return node.nodeIndex;
8639 var ns = this.nodes;
8640 for(var i = 0, len = ns.length; i < len; i++){
8651 * based on jquery fullcalendar
8655 Roo.bootstrap = Roo.bootstrap || {};
8657 * @class Roo.bootstrap.Calendar
8658 * @extends Roo.bootstrap.Component
8659 * Bootstrap Calendar class
8660 * @cfg {Boolean} loadMask (true|false) default false
8663 * Create a new Container
8664 * @param {Object} config The config object
8669 Roo.bootstrap.Calendar = function(config){
8670 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
8674 * Fires when a date is selected
8675 * @param {DatePicker} this
8676 * @param {Date} date The selected date
8680 * @event monthchange
8681 * Fires when the displayed month changes
8682 * @param {DatePicker} this
8683 * @param {Date} date The selected month
8685 'monthchange': true,
8688 * Fires when mouse over an event
8689 * @param {Calendar} this
8690 * @param {event} Event
8695 * Fires when the mouse leaves an
8696 * @param {Calendar} this
8702 * Fires when the mouse click an
8703 * @param {Calendar} this
8712 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
8715 * @cfg {Number} startDay
8716 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
8722 getAutoCreate : function(){
8725 var fc_button = function(name, corner, style, content ) {
8726 return Roo.apply({},{
8728 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
8730 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
8733 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
8741 style : 'width:100%',
8748 cls : 'fc-header-left',
8750 fc_button('prev', 'left', 'arrow', '‹' ),
8751 fc_button('next', 'right', 'arrow', '›' ),
8752 { tag: 'span', cls: 'fc-header-space' },
8753 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
8761 cls : 'fc-header-center',
8765 cls: 'fc-header-title',
8768 html : 'month / year'
8776 cls : 'fc-header-right',
8778 /* fc_button('month', 'left', '', 'month' ),
8779 fc_button('week', '', '', 'week' ),
8780 fc_button('day', 'right', '', 'day' )
8792 var cal_heads = function() {
8794 // fixme - handle this.
8796 for (var i =0; i < Date.dayNames.length; i++) {
8797 var d = Date.dayNames[i];
8800 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
8801 html : d.substring(0,3)
8805 ret[0].cls += ' fc-first';
8806 ret[6].cls += ' fc-last';
8809 var cal_cell = function(n) {
8812 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
8817 cls: 'fc-day-number',
8821 cls: 'fc-day-content',
8825 style: 'position: relative;' // height: 17px;
8837 var cal_rows = function() {
8840 for (var r = 0; r < 6; r++) {
8847 for (var i =0; i < Date.dayNames.length; i++) {
8848 var d = Date.dayNames[i];
8849 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
8852 row.cn[0].cls+=' fc-first';
8853 row.cn[0].cn[0].style = 'min-height:90px';
8854 row.cn[6].cls+=' fc-last';
8858 ret[0].cls += ' fc-first';
8859 ret[4].cls += ' fc-prev-last';
8860 ret[5].cls += ' fc-last';
8867 cls: 'fc-border-separate',
8868 style : 'width:100%',
8876 cls : 'fc-first fc-last',
8895 style : "position: relative;",
8898 cls : 'fc-view fc-view-month fc-grid',
8899 style : 'position: relative',
8900 unselectable : 'on',
8903 cls : 'fc-event-container',
8904 style : 'position:absolute;z-index:8;top:0;left:0;'
8922 initEvents : function()
8925 throw "can not find store for calendar";
8931 style: "text-align:center",
8935 style: "background-color:white;width:50%;margin:250 auto",
8939 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
8950 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
8952 var size = this.el.select('.fc-content', true).first().getSize();
8953 this.maskEl.setSize(size.width, size.height);
8954 this.maskEl.enableDisplayMode("block");
8959 this.store = Roo.factory(this.store, Roo.data);
8960 this.store.on('load', this.onLoad, this);
8961 this.store.on('beforeload', this.onBeforeLoad, this);
8965 this.cells = this.el.select('.fc-day',true);
8966 //Roo.log(this.cells);
8967 this.textNodes = this.el.query('.fc-day-number');
8968 this.cells.addClassOnOver('fc-state-hover');
8970 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
8971 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
8972 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
8973 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
8975 this.on('monthchange', this.onMonthChange, this);
8977 this.update(new Date().clearTime());
8980 resize : function() {
8981 var sz = this.el.getSize();
8983 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
8984 this.el.select('.fc-day-content div',true).setHeight(34);
8989 showPrevMonth : function(e){
8990 this.update(this.activeDate.add("mo", -1));
8992 showToday : function(e){
8993 this.update(new Date().clearTime());
8996 showNextMonth : function(e){
8997 this.update(this.activeDate.add("mo", 1));
9001 showPrevYear : function(){
9002 this.update(this.activeDate.add("y", -1));
9006 showNextYear : function(){
9007 this.update(this.activeDate.add("y", 1));
9012 update : function(date)
9014 var vd = this.activeDate;
9015 this.activeDate = date;
9016 // if(vd && this.el){
9017 // var t = date.getTime();
9018 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
9019 // Roo.log('using add remove');
9021 // this.fireEvent('monthchange', this, date);
9023 // this.cells.removeClass("fc-state-highlight");
9024 // this.cells.each(function(c){
9025 // if(c.dateValue == t){
9026 // c.addClass("fc-state-highlight");
9027 // setTimeout(function(){
9028 // try{c.dom.firstChild.focus();}catch(e){}
9038 var days = date.getDaysInMonth();
9040 var firstOfMonth = date.getFirstDateOfMonth();
9041 var startingPos = firstOfMonth.getDay()-this.startDay;
9043 if(startingPos < this.startDay){
9047 var pm = date.add(Date.MONTH, -1);
9048 var prevStart = pm.getDaysInMonth()-startingPos;
9050 this.cells = this.el.select('.fc-day',true);
9051 this.textNodes = this.el.query('.fc-day-number');
9052 this.cells.addClassOnOver('fc-state-hover');
9054 var cells = this.cells.elements;
9055 var textEls = this.textNodes;
9057 Roo.each(cells, function(cell){
9058 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
9061 days += startingPos;
9063 // convert everything to numbers so it's fast
9065 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
9068 //Roo.log(prevStart);
9070 var today = new Date().clearTime().getTime();
9071 var sel = date.clearTime().getTime();
9072 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
9073 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
9074 var ddMatch = this.disabledDatesRE;
9075 var ddText = this.disabledDatesText;
9076 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
9077 var ddaysText = this.disabledDaysText;
9078 var format = this.format;
9080 var setCellClass = function(cal, cell){
9082 //Roo.log('set Cell Class');
9084 var t = d.getTime();
9090 cell.className += " fc-today";
9091 cell.className += " fc-state-highlight";
9092 cell.title = cal.todayText;
9095 // disable highlight in other month..
9096 //cell.className += " fc-state-highlight";
9101 cell.className = " fc-state-disabled";
9102 cell.title = cal.minText;
9106 cell.className = " fc-state-disabled";
9107 cell.title = cal.maxText;
9111 if(ddays.indexOf(d.getDay()) != -1){
9112 cell.title = ddaysText;
9113 cell.className = " fc-state-disabled";
9116 if(ddMatch && format){
9117 var fvalue = d.dateFormat(format);
9118 if(ddMatch.test(fvalue)){
9119 cell.title = ddText.replace("%0", fvalue);
9120 cell.className = " fc-state-disabled";
9124 if (!cell.initialClassName) {
9125 cell.initialClassName = cell.dom.className;
9128 cell.dom.className = cell.initialClassName + ' ' + cell.className;
9133 for(; i < startingPos; i++) {
9134 textEls[i].innerHTML = (++prevStart);
9135 d.setDate(d.getDate()+1);
9137 cells[i].className = "fc-past fc-other-month";
9138 setCellClass(this, cells[i]);
9143 for(; i < days; i++){
9144 intDay = i - startingPos + 1;
9145 textEls[i].innerHTML = (intDay);
9146 d.setDate(d.getDate()+1);
9148 cells[i].className = ''; // "x-date-active";
9149 setCellClass(this, cells[i]);
9153 for(; i < 42; i++) {
9154 textEls[i].innerHTML = (++extraDays);
9155 d.setDate(d.getDate()+1);
9157 cells[i].className = "fc-future fc-other-month";
9158 setCellClass(this, cells[i]);
9161 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
9163 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
9165 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
9166 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
9169 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
9170 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
9173 this.fireEvent('monthchange', this, date);
9177 if(!this.internalRender){
9178 var main = this.el.dom.firstChild;
9179 var w = main.offsetWidth;
9180 this.el.setWidth(w + this.el.getBorderWidth("lr"));
9181 Roo.fly(main).setWidth(w);
9182 this.internalRender = true;
9183 // opera does not respect the auto grow header center column
9184 // then, after it gets a width opera refuses to recalculate
9185 // without a second pass
9186 if(Roo.isOpera && !this.secondPass){
9187 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
9188 this.secondPass = true;
9189 this.update.defer(10, this, [date]);
9196 findCell : function(dt) {
9197 dt = dt.clearTime().getTime();
9199 this.cells.each(function(c){
9200 //Roo.log("check " +c.dateValue + '?=' + dt);
9201 if(c.dateValue == dt){
9211 findCells : function(ev) {
9212 var s = ev.start.clone().clearTime().getTime();
9214 var e= ev.end.clone().clearTime().getTime();
9217 this.cells.each(function(c){
9218 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
9220 if(c.dateValue > e){
9223 if(c.dateValue < s){
9232 findBestRow: function(cells)
9236 for (var i =0 ; i < cells.length;i++) {
9237 ret = Math.max(cells[i].rows || 0,ret);
9244 addItem : function(ev)
9246 // look for vertical location slot in
9247 var cells = this.findCells(ev);
9249 ev.row = this.findBestRow(cells);
9251 // work out the location.
9255 for(var i =0; i < cells.length; i++) {
9263 if (crow.start.getY() == cells[i].getY()) {
9265 crow.end = cells[i];
9281 for (var i = 0; i < cells.length;i++) {
9282 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
9286 this.calevents.push(ev);
9289 clearEvents: function() {
9291 if(!this.calevents){
9295 Roo.each(this.cells.elements, function(c){
9299 Roo.each(this.calevents, function(e) {
9300 Roo.each(e.els, function(el) {
9301 el.un('mouseenter' ,this.onEventEnter, this);
9302 el.un('mouseleave' ,this.onEventLeave, this);
9309 renderEvents: function()
9311 // first make sure there is enough space..
9313 this.cells.each(function(c) {
9315 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
9318 for (var e = 0; e < this.calevents.length; e++) {
9319 var ev = this.calevents[e];
9320 var cells = ev.cells;
9323 for(var i =0; i < rows.length; i++) {
9326 // how many rows should it span..
9329 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
9330 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
9332 unselectable : "on",
9335 cls: 'fc-event-inner',
9339 cls: 'fc-event-time',
9340 html : cells.length > 1 ? '' : ev.time
9344 cls: 'fc-event-title',
9345 html : String.format('{0}', ev.title)
9352 cls: 'ui-resizable-handle ui-resizable-e',
9353 html : '  '
9359 cfg.cls += ' fc-event-start';
9361 if ((i+1) == rows.length) {
9362 cfg.cls += ' fc-event-end';
9365 var ctr = this.el.select('.fc-event-container',true).first();
9366 var cg = ctr.createChild(cfg);
9368 cg.on('mouseenter' ,this.onEventEnter, this, ev);
9369 cg.on('mouseleave' ,this.onEventLeave, this, ev);
9370 cg.on('click', this.onEventClick, this, ev);
9374 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
9375 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
9377 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
9378 cg.setWidth(ebox.right - sbox.x -2);
9386 onEventEnter: function (e, el,event,d) {
9387 this.fireEvent('evententer', this, el, event);
9390 onEventLeave: function (e, el,event,d) {
9391 this.fireEvent('eventleave', this, el, event);
9394 onEventClick: function (e, el,event,d) {
9395 this.fireEvent('eventclick', this, el, event);
9398 onMonthChange: function () {
9404 this.calevents = [];
9406 if(this.store.getCount() > 0){
9407 this.store.data.each(function(d){
9410 start: new Date(d.data.start_dt),
9411 end : new Date(d.data.end_dt),
9412 time : d.data.start_time,
9413 title : d.data.title,
9414 description : d.data.description,
9415 venue : d.data.venue
9420 this.renderEvents();
9427 onBeforeLoad: function()
9446 * @class Roo.bootstrap.Popover
9447 * @extends Roo.bootstrap.Component
9448 * Bootstrap Popover class
9449 * @cfg {String} html contents of the popover (or false to use children..)
9450 * @cfg {String} title of popover (or false to hide)
9451 * @cfg {String} placement how it is placed
9452 * @cfg {String} trigger click || hover (or false to trigger manually)
9453 * @cfg {String} over what (parent or false to trigger manually.)
9456 * Create a new Popover
9457 * @param {Object} config The config object
9460 Roo.bootstrap.Popover = function(config){
9461 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
9464 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
9466 title: 'Fill in a title',
9469 placement : 'right',
9470 trigger : 'hover', // hover
9474 can_build_overlaid : false,
9476 getChildContainer : function()
9478 return this.el.select('.popover-content',true).first();
9481 getAutoCreate : function(){
9482 Roo.log('make popover?');
9484 cls : 'popover roo-dynamic',
9485 style: 'display:block',
9491 cls : 'popover-inner',
9495 cls: 'popover-title',
9499 cls : 'popover-content',
9510 setTitle: function(str)
9512 this.el.select('.popover-title',true).first().dom.innerHTML = str;
9514 setContent: function(str)
9516 this.el.select('.popover-content',true).first().dom.innerHTML = str;
9518 // as it get's added to the bottom of the page.
9519 onRender : function(ct, position)
9521 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
9523 var cfg = Roo.apply({}, this.getAutoCreate());
9527 cfg.cls += ' ' + this.cls;
9530 cfg.style = this.style;
9532 Roo.log("adding to ")
9533 this.el = Roo.get(document.body).createChild(cfg, position);
9539 initEvents : function()
9541 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
9542 this.el.enableDisplayMode('block');
9544 if (this.over === false) {
9547 if (this.triggers === false) {
9550 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9551 var triggers = this.trigger ? this.trigger.split(' ') : [];
9552 Roo.each(triggers, function(trigger) {
9554 if (trigger == 'click') {
9555 on_el.on('click', this.toggle, this);
9556 } else if (trigger != 'manual') {
9557 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
9558 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
9560 on_el.on(eventIn ,this.enter, this);
9561 on_el.on(eventOut, this.leave, this);
9572 toggle : function () {
9573 this.hoverState == 'in' ? this.leave() : this.enter();
9576 enter : function () {
9579 clearTimeout(this.timeout);
9581 this.hoverState = 'in'
9583 if (!this.delay || !this.delay.show) {
9588 this.timeout = setTimeout(function () {
9589 if (_t.hoverState == 'in') {
9594 leave : function() {
9595 clearTimeout(this.timeout);
9597 this.hoverState = 'out'
9599 if (!this.delay || !this.delay.hide) {
9604 this.timeout = setTimeout(function () {
9605 if (_t.hoverState == 'out') {
9611 show : function (on_el)
9614 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9617 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
9618 if (this.html !== false) {
9619 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
9621 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
9622 if (!this.title.length) {
9623 this.el.select('.popover-title',true).hide();
9626 var placement = typeof this.placement == 'function' ?
9627 this.placement.call(this, this.el, on_el) :
9630 var autoToken = /\s?auto?\s?/i;
9631 var autoPlace = autoToken.test(placement);
9633 placement = placement.replace(autoToken, '') || 'top';
9637 //this.el.setXY([0,0]);
9639 this.el.dom.style.display='block';
9640 this.el.addClass(placement);
9642 //this.el.appendTo(on_el);
9644 var p = this.getPosition();
9645 var box = this.el.getBox();
9650 var align = Roo.bootstrap.Popover.alignment[placement]
9651 this.el.alignTo(on_el, align[0],align[1]);
9652 //var arrow = this.el.select('.arrow',true).first();
9653 //arrow.set(align[2],
9655 this.el.addClass('in');
9656 this.hoverState = null;
9658 if (this.el.hasClass('fade')) {
9665 this.el.setXY([0,0]);
9666 this.el.removeClass('in');
9673 Roo.bootstrap.Popover.alignment = {
9674 'left' : ['r-l', [-10,0], 'right'],
9675 'right' : ['l-r', [10,0], 'left'],
9676 'bottom' : ['t-b', [0,10], 'top'],
9677 'top' : [ 'b-t', [0,-10], 'bottom']
9688 * @class Roo.bootstrap.Progress
9689 * @extends Roo.bootstrap.Component
9690 * Bootstrap Progress class
9691 * @cfg {Boolean} striped striped of the progress bar
9692 * @cfg {Boolean} active animated of the progress bar
9696 * Create a new Progress
9697 * @param {Object} config The config object
9700 Roo.bootstrap.Progress = function(config){
9701 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
9704 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
9709 getAutoCreate : function(){
9717 cfg.cls += ' progress-striped';
9721 cfg.cls += ' active';
9740 * @class Roo.bootstrap.ProgressBar
9741 * @extends Roo.bootstrap.Component
9742 * Bootstrap ProgressBar class
9743 * @cfg {Number} aria_valuenow aria-value now
9744 * @cfg {Number} aria_valuemin aria-value min
9745 * @cfg {Number} aria_valuemax aria-value max
9746 * @cfg {String} label label for the progress bar
9747 * @cfg {String} panel (success | info | warning | danger )
9748 * @cfg {String} role role of the progress bar
9749 * @cfg {String} sr_only text
9753 * Create a new ProgressBar
9754 * @param {Object} config The config object
9757 Roo.bootstrap.ProgressBar = function(config){
9758 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
9761 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
9765 aria_valuemax : 100,
9771 getAutoCreate : function()
9776 cls: 'progress-bar',
9777 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
9789 cfg.role = this.role;
9792 if(this.aria_valuenow){
9793 cfg['aria-valuenow'] = this.aria_valuenow;
9796 if(this.aria_valuemin){
9797 cfg['aria-valuemin'] = this.aria_valuemin;
9800 if(this.aria_valuemax){
9801 cfg['aria-valuemax'] = this.aria_valuemax;
9804 if(this.label && !this.sr_only){
9805 cfg.html = this.label;
9809 cfg.cls += ' progress-bar-' + this.panel;
9815 update : function(aria_valuenow)
9817 this.aria_valuenow = aria_valuenow;
9819 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
9834 * @class Roo.bootstrap.TabPanel
9835 * @extends Roo.bootstrap.Component
9836 * Bootstrap TabPanel class
9837 * @cfg {Boolean} active panel active
9838 * @cfg {String} html panel content
9839 * @cfg {String} tabId tab relate id
9843 * Create a new TabPanel
9844 * @param {Object} config The config object
9847 Roo.bootstrap.TabPanel = function(config){
9848 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
9851 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
9857 getAutoCreate : function(){
9861 html: this.html || ''
9865 cfg.cls += ' active';
9869 cfg.tabId = this.tabId;
9887 * @class Roo.bootstrap.DateField
9888 * @extends Roo.bootstrap.Input
9889 * Bootstrap DateField class
9890 * @cfg {Number} weekStart default 0
9891 * @cfg {Number} weekStart default 0
9892 * @cfg {Number} viewMode default empty, (months|years)
9893 * @cfg {Number} minViewMode default empty, (months|years)
9894 * @cfg {Number} startDate default -Infinity
9895 * @cfg {Number} endDate default Infinity
9896 * @cfg {Boolean} todayHighlight default false
9897 * @cfg {Boolean} todayBtn default false
9898 * @cfg {Boolean} calendarWeeks default false
9899 * @cfg {Object} daysOfWeekDisabled default empty
9901 * @cfg {Boolean} keyboardNavigation default true
9902 * @cfg {String} language default en
9905 * Create a new DateField
9906 * @param {Object} config The config object
9909 Roo.bootstrap.DateField = function(config){
9910 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
9913 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
9916 * @cfg {String} format
9917 * The default date format string which can be overriden for localization support. The format must be
9918 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
9922 * @cfg {String} altFormats
9923 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
9924 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
9926 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
9934 todayHighlight : false,
9940 keyboardNavigation: true,
9942 calendarWeeks: false,
9944 startDate: -Infinity,
9948 daysOfWeekDisabled: [],
9954 return new Date(Date.UTC.apply(Date, arguments));
9957 UTCToday: function()
9959 var today = new Date();
9960 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
9963 getDate: function() {
9964 var d = this.getUTCDate();
9965 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
9968 getUTCDate: function() {
9972 setDate: function(d) {
9973 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
9976 setUTCDate: function(d) {
9978 this.setValue(this.formatDate(this.date));
9981 onRender: function(ct, position)
9984 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
9986 this.language = this.language || 'en';
9987 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
9988 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
9990 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
9991 this.format = this.format || 'm/d/y';
9992 this.isInline = false;
9993 this.isInput = true;
9994 this.component = this.el.select('.add-on', true).first() || false;
9995 this.component = (this.component && this.component.length === 0) ? false : this.component;
9996 this.hasInput = this.component && this.inputEL().length;
9998 if (typeof(this.minViewMode === 'string')) {
9999 switch (this.minViewMode) {
10001 this.minViewMode = 1;
10004 this.minViewMode = 2;
10007 this.minViewMode = 0;
10012 if (typeof(this.viewMode === 'string')) {
10013 switch (this.viewMode) {
10026 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
10028 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10030 this.picker().on('mousedown', this.onMousedown, this);
10031 this.picker().on('click', this.onClick, this);
10033 this.picker().addClass('datepicker-dropdown');
10035 this.startViewMode = this.viewMode;
10038 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
10039 if(!this.calendarWeeks){
10044 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
10045 v.attr('colspan', function(i, val){
10046 return parseInt(val) + 1;
10051 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
10053 this.setStartDate(this.startDate);
10054 this.setEndDate(this.endDate);
10056 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
10063 if(this.isInline) {
10068 picker : function()
10070 return this.el.select('.datepicker', true).first();
10073 fillDow: function()
10075 var dowCnt = this.weekStart;
10084 if(this.calendarWeeks){
10092 while (dowCnt < this.weekStart + 7) {
10096 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
10100 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
10103 fillMonths: function()
10106 var months = this.picker().select('>.datepicker-months td', true).first();
10108 months.dom.innerHTML = '';
10114 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
10117 months.createChild(month);
10122 update: function(){
10124 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
10126 if (this.date < this.startDate) {
10127 this.viewDate = new Date(this.startDate);
10128 } else if (this.date > this.endDate) {
10129 this.viewDate = new Date(this.endDate);
10131 this.viewDate = new Date(this.date);
10138 var d = new Date(this.viewDate),
10139 year = d.getUTCFullYear(),
10140 month = d.getUTCMonth(),
10141 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
10142 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
10143 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
10144 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
10145 currentDate = this.date && this.date.valueOf(),
10146 today = this.UTCToday();
10148 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
10150 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
10152 // this.picker.select('>tfoot th.today').
10153 // .text(dates[this.language].today)
10154 // .toggle(this.todayBtn !== false);
10156 this.updateNavArrows();
10159 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
10161 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
10163 prevMonth.setUTCDate(day);
10165 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
10167 var nextMonth = new Date(prevMonth);
10169 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
10171 nextMonth = nextMonth.valueOf();
10173 var fillMonths = false;
10175 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
10177 while(prevMonth.valueOf() < nextMonth) {
10180 if (prevMonth.getUTCDay() === this.weekStart) {
10182 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
10190 if(this.calendarWeeks){
10191 // ISO 8601: First week contains first thursday.
10192 // ISO also states week starts on Monday, but we can be more abstract here.
10194 // Start of current week: based on weekstart/current date
10195 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
10196 // Thursday of this week
10197 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
10198 // First Thursday of year, year from thursday
10199 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
10200 // Calendar week: ms between thursdays, div ms per day, div 7 days
10201 calWeek = (th - yth) / 864e5 / 7 + 1;
10203 fillMonths.cn.push({
10211 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
10213 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
10216 if (this.todayHighlight &&
10217 prevMonth.getUTCFullYear() == today.getFullYear() &&
10218 prevMonth.getUTCMonth() == today.getMonth() &&
10219 prevMonth.getUTCDate() == today.getDate()) {
10220 clsName += ' today';
10223 if (currentDate && prevMonth.valueOf() === currentDate) {
10224 clsName += ' active';
10227 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
10228 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
10229 clsName += ' disabled';
10232 fillMonths.cn.push({
10234 cls: 'day ' + clsName,
10235 html: prevMonth.getDate()
10238 prevMonth.setDate(prevMonth.getDate()+1);
10241 var currentYear = this.date && this.date.getUTCFullYear();
10242 var currentMonth = this.date && this.date.getUTCMonth();
10244 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
10246 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
10247 v.removeClass('active');
10249 if(currentYear === year && k === currentMonth){
10250 v.addClass('active');
10253 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
10254 v.addClass('disabled');
10260 year = parseInt(year/10, 10) * 10;
10262 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
10264 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
10267 for (var i = -1; i < 11; i++) {
10268 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
10270 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
10278 showMode: function(dir) {
10280 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
10282 Roo.each(this.picker().select('>div',true).elements, function(v){
10283 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10286 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
10291 if(this.isInline) return;
10293 this.picker().removeClass(['bottom', 'top']);
10295 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
10297 * place to the top of element!
10301 this.picker().addClass('top');
10302 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10307 this.picker().addClass('bottom');
10309 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10312 parseDate : function(value){
10313 if(!value || value instanceof Date){
10316 var v = Date.parseDate(value, this.format);
10317 if (!v && this.useIso) {
10318 v = Date.parseDate(value, 'Y-m-d');
10320 if(!v && this.altFormats){
10321 if(!this.altFormatsArray){
10322 this.altFormatsArray = this.altFormats.split("|");
10324 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
10325 v = Date.parseDate(value, this.altFormatsArray[i]);
10331 formatDate : function(date, fmt){
10332 return (!date || !(date instanceof Date)) ?
10333 date : date.dateFormat(fmt || this.format);
10336 onFocus : function()
10338 Roo.bootstrap.DateField.superclass.onFocus.call(this);
10342 onBlur : function()
10344 Roo.bootstrap.DateField.superclass.onBlur.call(this);
10350 this.picker().show();
10357 if(this.isInline) return;
10358 this.picker().hide();
10359 this.viewMode = this.startViewMode;
10364 onMousedown: function(e){
10365 e.stopPropagation();
10366 e.preventDefault();
10369 keyup: function(e){
10370 Roo.bootstrap.DateField.superclass.keyup.call(this);
10375 fireKey: function(e){
10376 if (!this.picker().isVisible()){
10377 if (e.keyCode == 27) // allow escape to hide and re-show picker
10381 var dateChanged = false,
10383 newDate, newViewDate;
10387 e.preventDefault();
10391 if (!this.keyboardNavigation) break;
10392 dir = e.keyCode == 37 ? -1 : 1;
10395 newDate = this.moveYear(this.date, dir);
10396 newViewDate = this.moveYear(this.viewDate, dir);
10397 } else if (e.shiftKey){
10398 newDate = this.moveMonth(this.date, dir);
10399 newViewDate = this.moveMonth(this.viewDate, dir);
10401 newDate = new Date(this.date);
10402 newDate.setUTCDate(this.date.getUTCDate() + dir);
10403 newViewDate = new Date(this.viewDate);
10404 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
10406 if (this.dateWithinRange(newDate)){
10407 this.date = newDate;
10408 this.viewDate = newViewDate;
10409 this.setValue(this.formatDate(this.date));
10411 e.preventDefault();
10412 dateChanged = true;
10417 if (!this.keyboardNavigation) break;
10418 dir = e.keyCode == 38 ? -1 : 1;
10420 newDate = this.moveYear(this.date, dir);
10421 newViewDate = this.moveYear(this.viewDate, dir);
10422 } else if (e.shiftKey){
10423 newDate = this.moveMonth(this.date, dir);
10424 newViewDate = this.moveMonth(this.viewDate, dir);
10426 newDate = new Date(this.date);
10427 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
10428 newViewDate = new Date(this.viewDate);
10429 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
10431 if (this.dateWithinRange(newDate)){
10432 this.date = newDate;
10433 this.viewDate = newViewDate;
10434 this.setValue(this.formatDate(this.date));
10436 e.preventDefault();
10437 dateChanged = true;
10441 this.setValue(this.formatDate(this.date));
10443 e.preventDefault();
10446 this.setValue(this.formatDate(this.date));
10453 onClick: function(e) {
10454 e.stopPropagation();
10455 e.preventDefault();
10457 var target = e.getTarget();
10459 if(target.nodeName.toLowerCase() === 'i'){
10460 target = Roo.get(target).dom.parentNode;
10463 var nodeName = target.nodeName;
10464 var className = target.className;
10465 var html = target.innerHTML;
10467 switch(nodeName.toLowerCase()) {
10469 switch(className) {
10475 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
10476 switch(this.viewMode){
10478 this.viewDate = this.moveMonth(this.viewDate, dir);
10482 this.viewDate = this.moveYear(this.viewDate, dir);
10488 var date = new Date();
10489 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
10491 this.setValue(this.formatDate(this.date));
10497 if (className.indexOf('disabled') === -1) {
10498 this.viewDate.setUTCDate(1);
10499 if (className.indexOf('month') !== -1) {
10500 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
10502 var year = parseInt(html, 10) || 0;
10503 this.viewDate.setUTCFullYear(year);
10512 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
10513 var day = parseInt(html, 10) || 1;
10514 var year = this.viewDate.getUTCFullYear(),
10515 month = this.viewDate.getUTCMonth();
10517 if (className.indexOf('old') !== -1) {
10524 } else if (className.indexOf('new') !== -1) {
10532 this.date = this.UTCDate(year, month, day,0,0,0,0);
10533 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
10535 this.setValue(this.formatDate(this.date));
10542 setStartDate: function(startDate){
10543 this.startDate = startDate || -Infinity;
10544 if (this.startDate !== -Infinity) {
10545 this.startDate = this.parseDate(this.startDate);
10548 this.updateNavArrows();
10551 setEndDate: function(endDate){
10552 this.endDate = endDate || Infinity;
10553 if (this.endDate !== Infinity) {
10554 this.endDate = this.parseDate(this.endDate);
10557 this.updateNavArrows();
10560 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
10561 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
10562 if (typeof(this.daysOfWeekDisabled) !== 'object') {
10563 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
10565 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
10566 return parseInt(d, 10);
10569 this.updateNavArrows();
10572 updateNavArrows: function() {
10573 var d = new Date(this.viewDate),
10574 year = d.getUTCFullYear(),
10575 month = d.getUTCMonth();
10577 Roo.each(this.picker().select('.prev', true).elements, function(v){
10579 switch (this.viewMode) {
10582 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
10588 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
10595 Roo.each(this.picker().select('.next', true).elements, function(v){
10597 switch (this.viewMode) {
10600 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
10606 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
10614 moveMonth: function(date, dir){
10615 if (!dir) return date;
10616 var new_date = new Date(date.valueOf()),
10617 day = new_date.getUTCDate(),
10618 month = new_date.getUTCMonth(),
10619 mag = Math.abs(dir),
10621 dir = dir > 0 ? 1 : -1;
10624 // If going back one month, make sure month is not current month
10625 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
10627 return new_date.getUTCMonth() == month;
10629 // If going forward one month, make sure month is as expected
10630 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
10632 return new_date.getUTCMonth() != new_month;
10634 new_month = month + dir;
10635 new_date.setUTCMonth(new_month);
10636 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
10637 if (new_month < 0 || new_month > 11)
10638 new_month = (new_month + 12) % 12;
10640 // For magnitudes >1, move one month at a time...
10641 for (var i=0; i<mag; i++)
10642 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
10643 new_date = this.moveMonth(new_date, dir);
10644 // ...then reset the day, keeping it in the new month
10645 new_month = new_date.getUTCMonth();
10646 new_date.setUTCDate(day);
10648 return new_month != new_date.getUTCMonth();
10651 // Common date-resetting loop -- if date is beyond end of month, make it
10654 new_date.setUTCDate(--day);
10655 new_date.setUTCMonth(new_month);
10660 moveYear: function(date, dir){
10661 return this.moveMonth(date, dir*12);
10664 dateWithinRange: function(date){
10665 return date >= this.startDate && date <= this.endDate;
10669 remove: function() {
10670 this.picker().remove();
10675 Roo.apply(Roo.bootstrap.DateField, {
10686 html: '<i class="icon-arrow-left"/>'
10696 html: '<i class="icon-arrow-right"/>'
10738 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
10739 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
10740 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
10741 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
10742 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
10755 navFnc: 'FullYear',
10760 navFnc: 'FullYear',
10765 Roo.apply(Roo.bootstrap.DateField, {
10769 cls: 'datepicker dropdown-menu',
10773 cls: 'datepicker-days',
10777 cls: 'table-condensed',
10779 Roo.bootstrap.DateField.head,
10783 Roo.bootstrap.DateField.footer
10790 cls: 'datepicker-months',
10794 cls: 'table-condensed',
10796 Roo.bootstrap.DateField.head,
10797 Roo.bootstrap.DateField.content,
10798 Roo.bootstrap.DateField.footer
10805 cls: 'datepicker-years',
10809 cls: 'table-condensed',
10811 Roo.bootstrap.DateField.head,
10812 Roo.bootstrap.DateField.content,
10813 Roo.bootstrap.DateField.footer
10832 * @class Roo.bootstrap.CheckBox
10833 * @extends Roo.bootstrap.Input
10834 * Bootstrap CheckBox class
10836 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
10837 * @cfg {String} boxLabel The text that appears beside the checkbox
10838 * @cfg {Boolean} checked initnal the element
10841 * Create a new CheckBox
10842 * @param {Object} config The config object
10845 Roo.bootstrap.CheckBox = function(config){
10846 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
10851 * Fires when the element is checked or unchecked.
10852 * @param {Roo.bootstrap.CheckBox} this This input
10853 * @param {Boolean} checked The new checked value
10859 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
10861 inputType: 'checkbox',
10867 getAutoCreate : function()
10869 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10875 cfg.cls = 'form-group' //input-group
10880 type : this.inputType,
10881 value : (!this.checked) ? this.valueOff : this.value,
10883 placeholder : this.placeholder || ''
10887 if (this.disabled) {
10888 input.disabled=true;
10892 input.checked = this.checked;
10896 input.name = this.name;
10900 input.cls += ' input-' + this.size;
10904 ['xs','sm','md','lg'].map(function(size){
10905 if (settings[size]) {
10906 cfg.cls += ' col-' + size + '-' + settings[size];
10910 var inputblock = input;
10912 if (this.before || this.after) {
10915 cls : 'input-group',
10919 inputblock.cn.push({
10921 cls : 'input-group-addon',
10925 inputblock.cn.push(input);
10927 inputblock.cn.push({
10929 cls : 'input-group-addon',
10936 if (align ==='left' && this.fieldLabel.length) {
10937 Roo.log("left and has label");
10943 cls : 'control-label col-md-' + this.labelWidth,
10944 html : this.fieldLabel
10948 cls : "col-md-" + (12 - this.labelWidth),
10955 } else if ( this.fieldLabel.length) {
10962 cls: 'control-label box-input-label',
10963 //cls : 'input-group-addon',
10964 html : this.fieldLabel
10974 Roo.log(" no label && no align");
10989 html: this.boxLabel
10998 * return the real input element.
11000 inputEl: function ()
11002 return this.el.select('input.form-box',true).first();
11005 initEvents : function()
11007 Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
11009 this.inputEl().on('click', this.onClick, this);
11013 onClick : function()
11015 this.setChecked(!this.checked);
11018 setChecked : function(state,suppressEvent)
11020 this.checked = state;
11022 if(suppressEvent !== true){
11023 this.fireEvent('check', this, state);
11026 this.inputEl().dom.value = state ? this.value : this.valueOff;
11040 * @class Roo.bootstrap.Radio
11041 * @extends Roo.bootstrap.CheckBox
11042 * Bootstrap Radio class
11045 * Create a new Radio
11046 * @param {Object} config The config object
11049 Roo.bootstrap.Radio = function(config){
11050 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
11054 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
11056 inputType: 'radio',
11058 getAutoCreate : function()
11060 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11066 cfg.cls = 'form-group' //input-group
11071 type : this.inputType,
11072 value : (!this.checked) ? this.valueOff : this.value,
11074 placeholder : this.placeholder || ''
11078 if (this.disabled) {
11079 input.disabled=true;
11083 input.checked = this.checked;
11087 input.name = this.name;
11091 input.cls += ' input-' + this.size;
11095 ['xs','sm','md','lg'].map(function(size){
11096 if (settings[size]) {
11097 cfg.cls += ' col-' + size + '-' + settings[size];
11101 var inputblock = input;
11103 if (this.before || this.after) {
11106 cls : 'input-group',
11110 inputblock.cn.push({
11112 cls : 'input-group-addon',
11116 inputblock.cn.push(input);
11118 inputblock.cn.push({
11120 cls : 'input-group-addon',
11127 if (align ==='left' && this.fieldLabel.length) {
11128 Roo.log("left and has label");
11134 cls : 'control-label col-md-' + this.labelWidth,
11135 html : this.fieldLabel
11139 cls : "col-md-" + (12 - this.labelWidth),
11146 } else if ( this.fieldLabel.length) {
11153 cls: 'control-label box-input-label',
11154 //cls : 'input-group-addon',
11155 html : this.fieldLabel
11165 Roo.log(" no label && no align");
11180 html: this.boxLabel
11188 onClick : function()
11190 this.setChecked(true);
11193 setChecked : function(state,suppressEvent)
11195 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
11199 this.checked = state;
11201 if(suppressEvent !== true){
11202 this.fireEvent('check', this, state);
11205 this.inputEl().dom.value = state ? this.value : this.valueOff;
11209 getGroupValue : function()
11211 if(typeof(this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true)) == 'undefined'){
11215 return this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true).value;
11219 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
11220 * @return {Mixed} value The field value
11222 getValue : function(){
11223 return this.getGroupValue();
11237 * @class Roo.bootstrap.HtmlEditor
11238 * @extends Roo.bootstrap.Component
11239 * Bootstrap HtmlEditor class
11242 * Create a new HtmlEditor
11243 * @param {Object} config The config object
11246 Roo.bootstrap.HtmlEditor = function(config){
11247 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
11252 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.Component, {
11254 getAutoCreate : function()
11258 // var toolbar = new Roo.bootstrap.ButtonGroup({
11262 // new Roo.bootstrap.Button({
11275 * @class Roo.bootstrap.Table.AbstractSelectionModel
11276 * @extends Roo.util.Observable
11277 * Abstract base class for grid SelectionModels. It provides the interface that should be
11278 * implemented by descendant classes. This class should not be directly instantiated.
11281 Roo.bootstrap.Table.AbstractSelectionModel = function(){
11282 this.locked = false;
11283 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
11287 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
11288 /** @ignore Called by the grid automatically. Do not call directly. */
11289 init : function(grid){
11295 * Locks the selections.
11298 this.locked = true;
11302 * Unlocks the selections.
11304 unlock : function(){
11305 this.locked = false;
11309 * Returns true if the selections are locked.
11310 * @return {Boolean}
11312 isLocked : function(){
11313 return this.locked;
11317 * @class Roo.bootstrap.Table.ColumnModel
11318 * @extends Roo.util.Observable
11319 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
11320 * the columns in the table.
11323 * @param {Object} config An Array of column config objects. See this class's
11324 * config objects for details.
11326 Roo.bootstrap.Table.ColumnModel = function(config){
11328 * The config passed into the constructor
11330 this.config = config;
11333 // if no id, create one
11334 // if the column does not have a dataIndex mapping,
11335 // map it to the order it is in the config
11336 for(var i = 0, len = config.length; i < len; i++){
11338 if(typeof c.dataIndex == "undefined"){
11341 if(typeof c.renderer == "string"){
11342 c.renderer = Roo.util.Format[c.renderer];
11344 if(typeof c.id == "undefined"){
11347 // if(c.editor && c.editor.xtype){
11348 // c.editor = Roo.factory(c.editor, Roo.grid);
11350 // if(c.editor && c.editor.isFormField){
11351 // c.editor = new Roo.grid.GridEditor(c.editor);
11354 this.lookup[c.id] = c;
11358 * The width of columns which have no width specified (defaults to 100)
11361 this.defaultWidth = 100;
11364 * Default sortable of columns which have no sortable specified (defaults to false)
11367 this.defaultSortable = false;
11371 * @event widthchange
11372 * Fires when the width of a column changes.
11373 * @param {ColumnModel} this
11374 * @param {Number} columnIndex The column index
11375 * @param {Number} newWidth The new width
11377 "widthchange": true,
11379 * @event headerchange
11380 * Fires when the text of a header changes.
11381 * @param {ColumnModel} this
11382 * @param {Number} columnIndex The column index
11383 * @param {Number} newText The new header text
11385 "headerchange": true,
11387 * @event hiddenchange
11388 * Fires when a column is hidden or "unhidden".
11389 * @param {ColumnModel} this
11390 * @param {Number} columnIndex The column index
11391 * @param {Boolean} hidden true if hidden, false otherwise
11393 "hiddenchange": true,
11395 * @event columnmoved
11396 * Fires when a column is moved.
11397 * @param {ColumnModel} this
11398 * @param {Number} oldIndex
11399 * @param {Number} newIndex
11401 "columnmoved" : true,
11403 * @event columlockchange
11404 * Fires when a column's locked state is changed
11405 * @param {ColumnModel} this
11406 * @param {Number} colIndex
11407 * @param {Boolean} locked true if locked
11409 "columnlockchange" : true
11411 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
11413 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
11415 * @cfg {String} header The header text to display in the Grid view.
11418 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
11419 * {@link Roo.data.Record} definition from which to draw the column's value. If not
11420 * specified, the column's index is used as an index into the Record's data Array.
11423 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
11424 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
11427 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
11428 * Defaults to the value of the {@link #defaultSortable} property.
11429 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
11432 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
11435 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
11438 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
11441 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
11444 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
11445 * given the cell's data value. See {@link #setRenderer}. If not specified, the
11446 * default renderer uses the raw data value.
11449 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
11453 * Returns the id of the column at the specified index.
11454 * @param {Number} index The column index
11455 * @return {String} the id
11457 getColumnId : function(index){
11458 return this.config[index].id;
11462 * Returns the column for a specified id.
11463 * @param {String} id The column id
11464 * @return {Object} the column
11466 getColumnById : function(id){
11467 return this.lookup[id];
11472 * Returns the column for a specified dataIndex.
11473 * @param {String} dataIndex The column dataIndex
11474 * @return {Object|Boolean} the column or false if not found
11476 getColumnByDataIndex: function(dataIndex){
11477 var index = this.findColumnIndex(dataIndex);
11478 return index > -1 ? this.config[index] : false;
11482 * Returns the index for a specified column id.
11483 * @param {String} id The column id
11484 * @return {Number} the index, or -1 if not found
11486 getIndexById : function(id){
11487 for(var i = 0, len = this.config.length; i < len; i++){
11488 if(this.config[i].id == id){
11496 * Returns the index for a specified column dataIndex.
11497 * @param {String} dataIndex The column dataIndex
11498 * @return {Number} the index, or -1 if not found
11501 findColumnIndex : function(dataIndex){
11502 for(var i = 0, len = this.config.length; i < len; i++){
11503 if(this.config[i].dataIndex == dataIndex){
11511 moveColumn : function(oldIndex, newIndex){
11512 var c = this.config[oldIndex];
11513 this.config.splice(oldIndex, 1);
11514 this.config.splice(newIndex, 0, c);
11515 this.dataMap = null;
11516 this.fireEvent("columnmoved", this, oldIndex, newIndex);
11519 isLocked : function(colIndex){
11520 return this.config[colIndex].locked === true;
11523 setLocked : function(colIndex, value, suppressEvent){
11524 if(this.isLocked(colIndex) == value){
11527 this.config[colIndex].locked = value;
11528 if(!suppressEvent){
11529 this.fireEvent("columnlockchange", this, colIndex, value);
11533 getTotalLockedWidth : function(){
11534 var totalWidth = 0;
11535 for(var i = 0; i < this.config.length; i++){
11536 if(this.isLocked(i) && !this.isHidden(i)){
11537 this.totalWidth += this.getColumnWidth(i);
11543 getLockedCount : function(){
11544 for(var i = 0, len = this.config.length; i < len; i++){
11545 if(!this.isLocked(i)){
11552 * Returns the number of columns.
11555 getColumnCount : function(visibleOnly){
11556 if(visibleOnly === true){
11558 for(var i = 0, len = this.config.length; i < len; i++){
11559 if(!this.isHidden(i)){
11565 return this.config.length;
11569 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
11570 * @param {Function} fn
11571 * @param {Object} scope (optional)
11572 * @return {Array} result
11574 getColumnsBy : function(fn, scope){
11576 for(var i = 0, len = this.config.length; i < len; i++){
11577 var c = this.config[i];
11578 if(fn.call(scope||this, c, i) === true){
11586 * Returns true if the specified column is sortable.
11587 * @param {Number} col The column index
11588 * @return {Boolean}
11590 isSortable : function(col){
11591 if(typeof this.config[col].sortable == "undefined"){
11592 return this.defaultSortable;
11594 return this.config[col].sortable;
11598 * Returns the rendering (formatting) function defined for the column.
11599 * @param {Number} col The column index.
11600 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
11602 getRenderer : function(col){
11603 if(!this.config[col].renderer){
11604 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
11606 return this.config[col].renderer;
11610 * Sets the rendering (formatting) function for a column.
11611 * @param {Number} col The column index
11612 * @param {Function} fn The function to use to process the cell's raw data
11613 * to return HTML markup for the grid view. The render function is called with
11614 * the following parameters:<ul>
11615 * <li>Data value.</li>
11616 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
11617 * <li>css A CSS style string to apply to the table cell.</li>
11618 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
11619 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
11620 * <li>Row index</li>
11621 * <li>Column index</li>
11622 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
11624 setRenderer : function(col, fn){
11625 this.config[col].renderer = fn;
11629 * Returns the width for the specified column.
11630 * @param {Number} col The column index
11633 getColumnWidth : function(col){
11634 return this.config[col].width * 1 || this.defaultWidth;
11638 * Sets the width for a column.
11639 * @param {Number} col The column index
11640 * @param {Number} width The new width
11642 setColumnWidth : function(col, width, suppressEvent){
11643 this.config[col].width = width;
11644 this.totalWidth = null;
11645 if(!suppressEvent){
11646 this.fireEvent("widthchange", this, col, width);
11651 * Returns the total width of all columns.
11652 * @param {Boolean} includeHidden True to include hidden column widths
11655 getTotalWidth : function(includeHidden){
11656 if(!this.totalWidth){
11657 this.totalWidth = 0;
11658 for(var i = 0, len = this.config.length; i < len; i++){
11659 if(includeHidden || !this.isHidden(i)){
11660 this.totalWidth += this.getColumnWidth(i);
11664 return this.totalWidth;
11668 * Returns the header for the specified column.
11669 * @param {Number} col The column index
11672 getColumnHeader : function(col){
11673 return this.config[col].header;
11677 * Sets the header for a column.
11678 * @param {Number} col The column index
11679 * @param {String} header The new header
11681 setColumnHeader : function(col, header){
11682 this.config[col].header = header;
11683 this.fireEvent("headerchange", this, col, header);
11687 * Returns the tooltip for the specified column.
11688 * @param {Number} col The column index
11691 getColumnTooltip : function(col){
11692 return this.config[col].tooltip;
11695 * Sets the tooltip for a column.
11696 * @param {Number} col The column index
11697 * @param {String} tooltip The new tooltip
11699 setColumnTooltip : function(col, tooltip){
11700 this.config[col].tooltip = tooltip;
11704 * Returns the dataIndex for the specified column.
11705 * @param {Number} col The column index
11708 getDataIndex : function(col){
11709 return this.config[col].dataIndex;
11713 * Sets the dataIndex for a column.
11714 * @param {Number} col The column index
11715 * @param {Number} dataIndex The new dataIndex
11717 setDataIndex : function(col, dataIndex){
11718 this.config[col].dataIndex = dataIndex;
11724 * Returns true if the cell is editable.
11725 * @param {Number} colIndex The column index
11726 * @param {Number} rowIndex The row index
11727 * @return {Boolean}
11729 isCellEditable : function(colIndex, rowIndex){
11730 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
11734 * Returns the editor defined for the cell/column.
11735 * return false or null to disable editing.
11736 * @param {Number} colIndex The column index
11737 * @param {Number} rowIndex The row index
11740 getCellEditor : function(colIndex, rowIndex){
11741 return this.config[colIndex].editor;
11745 * Sets if a column is editable.
11746 * @param {Number} col The column index
11747 * @param {Boolean} editable True if the column is editable
11749 setEditable : function(col, editable){
11750 this.config[col].editable = editable;
11755 * Returns true if the column is hidden.
11756 * @param {Number} colIndex The column index
11757 * @return {Boolean}
11759 isHidden : function(colIndex){
11760 return this.config[colIndex].hidden;
11765 * Returns true if the column width cannot be changed
11767 isFixed : function(colIndex){
11768 return this.config[colIndex].fixed;
11772 * Returns true if the column can be resized
11773 * @return {Boolean}
11775 isResizable : function(colIndex){
11776 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
11779 * Sets if a column is hidden.
11780 * @param {Number} colIndex The column index
11781 * @param {Boolean} hidden True if the column is hidden
11783 setHidden : function(colIndex, hidden){
11784 this.config[colIndex].hidden = hidden;
11785 this.totalWidth = null;
11786 this.fireEvent("hiddenchange", this, colIndex, hidden);
11790 * Sets the editor for a column.
11791 * @param {Number} col The column index
11792 * @param {Object} editor The editor object
11794 setEditor : function(col, editor){
11795 this.config[col].editor = editor;
11799 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
11800 if(typeof value == "string" && value.length < 1){
11806 // Alias for backwards compatibility
11807 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
11810 * @extends Roo.bootstrap.Table.AbstractSelectionModel
11811 * @class Roo.bootstrap.Table.RowSelectionModel
11812 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
11813 * It supports multiple selections and keyboard selection/navigation.
11815 * @param {Object} config
11818 Roo.bootstrap.Table.RowSelectionModel = function(config){
11819 Roo.apply(this, config);
11820 this.selections = new Roo.util.MixedCollection(false, function(o){
11825 this.lastActive = false;
11829 * @event selectionchange
11830 * Fires when the selection changes
11831 * @param {SelectionModel} this
11833 "selectionchange" : true,
11835 * @event afterselectionchange
11836 * Fires after the selection changes (eg. by key press or clicking)
11837 * @param {SelectionModel} this
11839 "afterselectionchange" : true,
11841 * @event beforerowselect
11842 * Fires when a row is selected being selected, return false to cancel.
11843 * @param {SelectionModel} this
11844 * @param {Number} rowIndex The selected index
11845 * @param {Boolean} keepExisting False if other selections will be cleared
11847 "beforerowselect" : true,
11850 * Fires when a row is selected.
11851 * @param {SelectionModel} this
11852 * @param {Number} rowIndex The selected index
11853 * @param {Roo.data.Record} r The record
11855 "rowselect" : true,
11857 * @event rowdeselect
11858 * Fires when a row is deselected.
11859 * @param {SelectionModel} this
11860 * @param {Number} rowIndex The selected index
11862 "rowdeselect" : true
11864 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
11865 this.locked = false;
11868 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
11870 * @cfg {Boolean} singleSelect
11871 * True to allow selection of only one row at a time (defaults to false)
11873 singleSelect : false,
11876 initEvents : function(){
11878 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
11879 this.grid.on("mousedown", this.handleMouseDown, this);
11880 }else{ // allow click to work like normal
11881 this.grid.on("rowclick", this.handleDragableRowClick, this);
11884 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
11885 "up" : function(e){
11887 this.selectPrevious(e.shiftKey);
11888 }else if(this.last !== false && this.lastActive !== false){
11889 var last = this.last;
11890 this.selectRange(this.last, this.lastActive-1);
11891 this.grid.getView().focusRow(this.lastActive);
11892 if(last !== false){
11896 this.selectFirstRow();
11898 this.fireEvent("afterselectionchange", this);
11900 "down" : function(e){
11902 this.selectNext(e.shiftKey);
11903 }else if(this.last !== false && this.lastActive !== false){
11904 var last = this.last;
11905 this.selectRange(this.last, this.lastActive+1);
11906 this.grid.getView().focusRow(this.lastActive);
11907 if(last !== false){
11911 this.selectFirstRow();
11913 this.fireEvent("afterselectionchange", this);
11918 var view = this.grid.view;
11919 view.on("refresh", this.onRefresh, this);
11920 view.on("rowupdated", this.onRowUpdated, this);
11921 view.on("rowremoved", this.onRemove, this);
11925 onRefresh : function(){
11926 var ds = this.grid.dataSource, i, v = this.grid.view;
11927 var s = this.selections;
11928 s.each(function(r){
11929 if((i = ds.indexOfId(r.id)) != -1){
11938 onRemove : function(v, index, r){
11939 this.selections.remove(r);
11943 onRowUpdated : function(v, index, r){
11944 if(this.isSelected(r)){
11945 v.onRowSelect(index);
11951 * @param {Array} records The records to select
11952 * @param {Boolean} keepExisting (optional) True to keep existing selections
11954 selectRecords : function(records, keepExisting){
11956 this.clearSelections();
11958 var ds = this.grid.dataSource;
11959 for(var i = 0, len = records.length; i < len; i++){
11960 this.selectRow(ds.indexOf(records[i]), true);
11965 * Gets the number of selected rows.
11968 getCount : function(){
11969 return this.selections.length;
11973 * Selects the first row in the grid.
11975 selectFirstRow : function(){
11980 * Select the last row.
11981 * @param {Boolean} keepExisting (optional) True to keep existing selections
11983 selectLastRow : function(keepExisting){
11984 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
11988 * Selects the row immediately following the last selected row.
11989 * @param {Boolean} keepExisting (optional) True to keep existing selections
11991 selectNext : function(keepExisting){
11992 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
11993 this.selectRow(this.last+1, keepExisting);
11994 this.grid.getView().focusRow(this.last);
11999 * Selects the row that precedes the last selected row.
12000 * @param {Boolean} keepExisting (optional) True to keep existing selections
12002 selectPrevious : function(keepExisting){
12004 this.selectRow(this.last-1, keepExisting);
12005 this.grid.getView().focusRow(this.last);
12010 * Returns the selected records
12011 * @return {Array} Array of selected records
12013 getSelections : function(){
12014 return [].concat(this.selections.items);
12018 * Returns the first selected record.
12021 getSelected : function(){
12022 return this.selections.itemAt(0);
12027 * Clears all selections.
12029 clearSelections : function(fast){
12030 if(this.locked) return;
12032 var ds = this.grid.dataSource;
12033 var s = this.selections;
12034 s.each(function(r){
12035 this.deselectRow(ds.indexOfId(r.id));
12039 this.selections.clear();
12046 * Selects all rows.
12048 selectAll : function(){
12049 if(this.locked) return;
12050 this.selections.clear();
12051 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
12052 this.selectRow(i, true);
12057 * Returns True if there is a selection.
12058 * @return {Boolean}
12060 hasSelection : function(){
12061 return this.selections.length > 0;
12065 * Returns True if the specified row is selected.
12066 * @param {Number/Record} record The record or index of the record to check
12067 * @return {Boolean}
12069 isSelected : function(index){
12070 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
12071 return (r && this.selections.key(r.id) ? true : false);
12075 * Returns True if the specified record id is selected.
12076 * @param {String} id The id of record to check
12077 * @return {Boolean}
12079 isIdSelected : function(id){
12080 return (this.selections.key(id) ? true : false);
12084 handleMouseDown : function(e, t){
12085 var view = this.grid.getView(), rowIndex;
12086 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
12089 if(e.shiftKey && this.last !== false){
12090 var last = this.last;
12091 this.selectRange(last, rowIndex, e.ctrlKey);
12092 this.last = last; // reset the last
12093 view.focusRow(rowIndex);
12095 var isSelected = this.isSelected(rowIndex);
12096 if(e.button !== 0 && isSelected){
12097 view.focusRow(rowIndex);
12098 }else if(e.ctrlKey && isSelected){
12099 this.deselectRow(rowIndex);
12100 }else if(!isSelected){
12101 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
12102 view.focusRow(rowIndex);
12105 this.fireEvent("afterselectionchange", this);
12108 handleDragableRowClick : function(grid, rowIndex, e)
12110 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
12111 this.selectRow(rowIndex, false);
12112 grid.view.focusRow(rowIndex);
12113 this.fireEvent("afterselectionchange", this);
12118 * Selects multiple rows.
12119 * @param {Array} rows Array of the indexes of the row to select
12120 * @param {Boolean} keepExisting (optional) True to keep existing selections
12122 selectRows : function(rows, keepExisting){
12124 this.clearSelections();
12126 for(var i = 0, len = rows.length; i < len; i++){
12127 this.selectRow(rows[i], true);
12132 * Selects a range of rows. All rows in between startRow and endRow are also selected.
12133 * @param {Number} startRow The index of the first row in the range
12134 * @param {Number} endRow The index of the last row in the range
12135 * @param {Boolean} keepExisting (optional) True to retain existing selections
12137 selectRange : function(startRow, endRow, keepExisting){
12138 if(this.locked) return;
12140 this.clearSelections();
12142 if(startRow <= endRow){
12143 for(var i = startRow; i <= endRow; i++){
12144 this.selectRow(i, true);
12147 for(var i = startRow; i >= endRow; i--){
12148 this.selectRow(i, true);
12154 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
12155 * @param {Number} startRow The index of the first row in the range
12156 * @param {Number} endRow The index of the last row in the range
12158 deselectRange : function(startRow, endRow, preventViewNotify){
12159 if(this.locked) return;
12160 for(var i = startRow; i <= endRow; i++){
12161 this.deselectRow(i, preventViewNotify);
12167 * @param {Number} row The index of the row to select
12168 * @param {Boolean} keepExisting (optional) True to keep existing selections
12170 selectRow : function(index, keepExisting, preventViewNotify){
12171 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
12172 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
12173 if(!keepExisting || this.singleSelect){
12174 this.clearSelections();
12176 var r = this.grid.dataSource.getAt(index);
12177 this.selections.add(r);
12178 this.last = this.lastActive = index;
12179 if(!preventViewNotify){
12180 this.grid.getView().onRowSelect(index);
12182 this.fireEvent("rowselect", this, index, r);
12183 this.fireEvent("selectionchange", this);
12189 * @param {Number} row The index of the row to deselect
12191 deselectRow : function(index, preventViewNotify){
12192 if(this.locked) return;
12193 if(this.last == index){
12196 if(this.lastActive == index){
12197 this.lastActive = false;
12199 var r = this.grid.dataSource.getAt(index);
12200 this.selections.remove(r);
12201 if(!preventViewNotify){
12202 this.grid.getView().onRowDeselect(index);
12204 this.fireEvent("rowdeselect", this, index);
12205 this.fireEvent("selectionchange", this);
12209 restoreLast : function(){
12211 this.last = this._last;
12216 acceptsNav : function(row, col, cm){
12217 return !cm.isHidden(col) && cm.isCellEditable(col, row);
12221 onEditorKey : function(field, e){
12222 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
12227 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
12229 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
12231 }else if(k == e.ENTER && !e.ctrlKey){
12235 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
12237 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
12239 }else if(k == e.ESC){
12243 g.startEditing(newCell[0], newCell[1]);