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);
3235 if(this.fireEvent('beforeaction', this, action) !== false){
3236 this.beforeAction(action);
3237 action.run.defer(100, action);
3243 beforeAction : function(action){
3244 var o = action.options;
3246 // not really supported yet.. ??
3248 //if(this.waitMsgTarget === true){
3249 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
3250 //}else if(this.waitMsgTarget){
3251 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
3252 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
3254 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
3260 afterAction : function(action, success){
3261 this.activeAction = null;
3262 var o = action.options;
3264 //if(this.waitMsgTarget === true){
3266 //}else if(this.waitMsgTarget){
3267 // this.waitMsgTarget.unmask();
3269 // Roo.MessageBox.updateProgress(1);
3270 // Roo.MessageBox.hide();
3277 Roo.callback(o.success, o.scope, [this, action]);
3278 this.fireEvent('actioncomplete', this, action);
3282 // failure condition..
3283 // we have a scenario where updates need confirming.
3284 // eg. if a locking scenario exists..
3285 // we look for { errors : { needs_confirm : true }} in the response.
3287 (typeof(action.result) != 'undefined') &&
3288 (typeof(action.result.errors) != 'undefined') &&
3289 (typeof(action.result.errors.needs_confirm) != 'undefined')
3292 Roo.log("not supported yet");
3295 Roo.MessageBox.confirm(
3296 "Change requires confirmation",
3297 action.result.errorMsg,
3302 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
3312 Roo.callback(o.failure, o.scope, [this, action]);
3313 // show an error message if no failed handler is set..
3314 if (!this.hasListener('actionfailed')) {
3315 Roo.log("need to add dialog support");
3317 Roo.MessageBox.alert("Error",
3318 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
3319 action.result.errorMsg :
3320 "Saving Failed, please check your entries or try again"
3325 this.fireEvent('actionfailed', this, action);
3330 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
3331 * @param {String} id The value to search for
3334 findField : function(id){
3335 var items = this.getItems();
3336 var field = items.get(id);
3338 items.each(function(f){
3339 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
3346 return field || null;
3349 * Mark fields in this form invalid in bulk.
3350 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
3351 * @return {BasicForm} this
3353 markInvalid : function(errors){
3354 if(errors instanceof Array){
3355 for(var i = 0, len = errors.length; i < len; i++){
3356 var fieldError = errors[i];
3357 var f = this.findField(fieldError.id);
3359 f.markInvalid(fieldError.msg);
3365 if(typeof errors[id] != 'function' && (field = this.findField(id))){
3366 field.markInvalid(errors[id]);
3370 //Roo.each(this.childForms || [], function (f) {
3371 // f.markInvalid(errors);
3378 * Set values for fields in this form in bulk.
3379 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
3380 * @return {BasicForm} this
3382 setValues : function(values){
3383 if(values instanceof Array){ // array of objects
3384 for(var i = 0, len = values.length; i < len; i++){
3386 var f = this.findField(v.id);
3388 f.setValue(v.value);
3389 if(this.trackResetOnLoad){
3390 f.originalValue = f.getValue();
3394 }else{ // object hash
3397 if(typeof values[id] != 'function' && (field = this.findField(id))){
3399 if (field.setFromData &&
3401 field.displayField &&
3402 // combos' with local stores can
3403 // be queried via setValue()
3404 // to set their value..
3405 (field.store && !field.store.isLocal)
3409 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
3410 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
3411 field.setFromData(sd);
3414 field.setValue(values[id]);
3418 if(this.trackResetOnLoad){
3419 field.originalValue = field.getValue();
3425 //Roo.each(this.childForms || [], function (f) {
3426 // f.setValues(values);
3433 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
3434 * they are returned as an array.
3435 * @param {Boolean} asString
3438 getValues : function(asString){
3439 //if (this.childForms) {
3440 // copy values from the child forms
3441 // Roo.each(this.childForms, function (f) {
3442 // this.setValues(f.getValues());
3448 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
3449 if(asString === true){
3452 return Roo.urlDecode(fs);
3456 * Returns the fields in this form as an object with key/value pairs.
3457 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
3460 getFieldValues : function(with_hidden)
3462 var items = this.getItems();
3464 items.each(function(f){
3468 var v = f.getValue();
3469 if (f.inputType =='radio') {
3470 if (typeof(ret[f.getName()]) == 'undefined') {
3471 ret[f.getName()] = ''; // empty..
3474 if (!f.el.dom.checked) {
3482 // not sure if this supported any more..
3483 if ((typeof(v) == 'object') && f.getRawValue) {
3484 v = f.getRawValue() ; // dates..
3486 // combo boxes where name != hiddenName...
3487 if (f.name != f.getName()) {
3488 ret[f.name] = f.getRawValue();
3490 ret[f.getName()] = v;
3497 * Clears all invalid messages in this form.
3498 * @return {BasicForm} this
3500 clearInvalid : function(){
3501 var items = this.getItems();
3503 items.each(function(f){
3514 * @return {BasicForm} this
3517 var items = this.getItems();
3518 items.each(function(f){
3522 Roo.each(this.childForms || [], function (f) {
3529 getItems : function()
3531 var r=new Roo.util.MixedCollection(false, function(o){
3532 return o.id || (o.id = Roo.id());
3534 var iter = function(el) {
3541 Roo.each(el.items,function(e) {
3560 * Ext JS Library 1.1.1
3561 * Copyright(c) 2006-2007, Ext JS, LLC.
3563 * Originally Released Under LGPL - original licence link has changed is not relivant.
3566 * <script type="text/javascript">
3569 * @class Roo.form.VTypes
3570 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
3573 Roo.form.VTypes = function(){
3574 // closure these in so they are only created once.
3575 var alpha = /^[a-zA-Z_]+$/;
3576 var alphanum = /^[a-zA-Z0-9_]+$/;
3577 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
3578 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
3580 // All these messages and functions are configurable
3583 * The function used to validate email addresses
3584 * @param {String} value The email address
3586 'email' : function(v){
3587 return email.test(v);
3590 * The error text to display when the email validation function returns false
3593 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
3595 * The keystroke filter mask to be applied on email input
3598 'emailMask' : /[a-z0-9_\.\-@]/i,
3601 * The function used to validate URLs
3602 * @param {String} value The URL
3604 'url' : function(v){
3608 * The error text to display when the url validation function returns false
3611 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
3614 * The function used to validate alpha values
3615 * @param {String} value The value
3617 'alpha' : function(v){
3618 return alpha.test(v);
3621 * The error text to display when the alpha validation function returns false
3624 'alphaText' : 'This field should only contain letters and _',
3626 * The keystroke filter mask to be applied on alpha input
3629 'alphaMask' : /[a-z_]/i,
3632 * The function used to validate alphanumeric values
3633 * @param {String} value The value
3635 'alphanum' : function(v){
3636 return alphanum.test(v);
3639 * The error text to display when the alphanumeric validation function returns false
3642 'alphanumText' : 'This field should only contain letters, numbers and _',
3644 * The keystroke filter mask to be applied on alphanumeric input
3647 'alphanumMask' : /[a-z0-9_]/i
3657 * @class Roo.bootstrap.Input
3658 * @extends Roo.bootstrap.Component
3659 * Bootstrap Input class
3660 * @cfg {Boolean} disabled is it disabled
3661 * @cfg {String} fieldLabel - the label associated
3662 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3663 * @cfg {String} name name of the input
3664 * @cfg {string} fieldLabel - the label associated
3665 * @cfg {string} inputType - input / file submit ...
3666 * @cfg {string} placeholder - placeholder to put in text.
3667 * @cfg {string} before - input group add on before
3668 * @cfg {string} after - input group add on after
3669 * @cfg {string} size - (lg|sm) or leave empty..
3670 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3671 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3672 * @cfg {Number} md colspan out of 12 for computer-sized screens
3673 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3674 * @cfg {string} value default value of the input
3675 * @cfg {Number} labelWidth set the width of label (0-12)
3676 * @cfg {String} labelAlign (top|left)
3680 * Create a new Input
3681 * @param {Object} config The config object
3684 Roo.bootstrap.Input = function(config){
3685 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3690 * Fires when this field receives input focus.
3691 * @param {Roo.form.Field} this
3696 * Fires when this field loses input focus.
3697 * @param {Roo.form.Field} this
3702 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3703 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3704 * @param {Roo.form.Field} this
3705 * @param {Roo.EventObject} e The event object
3710 * Fires just before the field blurs if the field value has changed.
3711 * @param {Roo.form.Field} this
3712 * @param {Mixed} newValue The new value
3713 * @param {Mixed} oldValue The original value
3718 * Fires after the field has been marked as invalid.
3719 * @param {Roo.form.Field} this
3720 * @param {String} msg The validation message
3725 * Fires after the field has been validated with no errors.
3726 * @param {Roo.form.Field} this
3731 * Fires after the key up
3732 * @param {Roo.form.Field} this
3733 * @param {Roo.EventObject} e The event Object
3739 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3741 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3742 automatic validation (defaults to "keyup").
3744 validationEvent : "keyup",
3746 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3748 validateOnBlur : true,
3750 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3752 validationDelay : 250,
3754 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3756 focusClass : "x-form-focus", // not needed???
3760 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3762 invalidClass : "has-error",
3765 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3767 selectOnFocus : false,
3770 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3774 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3779 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3781 disableKeyFilter : false,
3784 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3788 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3792 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3794 blankText : "This field is required",
3797 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3801 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3803 maxLength : Number.MAX_VALUE,
3805 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3807 minLengthText : "The minimum length for this field is {0}",
3809 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3811 maxLengthText : "The maximum length for this field is {0}",
3815 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3816 * If available, this function will be called only after the basic validators all return true, and will be passed the
3817 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3821 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3822 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3823 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
3827 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3849 parentLabelAlign : function()
3852 while (parent.parent()) {
3853 parent = parent.parent();
3854 if (typeof(parent.labelAlign) !='undefined') {
3855 return parent.labelAlign;
3862 getAutoCreate : function(){
3864 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
3870 if(this.inputType != 'hidden'){
3871 cfg.cls = 'form-group' //input-group
3877 type : this.inputType,
3879 cls : 'form-control',
3880 placeholder : this.placeholder || ''
3884 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
3885 input.maxLength = this.maxLength;
3888 if (this.disabled) {
3889 input.disabled=true;
3893 input.name = this.name;
3896 input.cls += ' input-' + this.size;
3899 ['xs','sm','md','lg'].map(function(size){
3900 if (settings[size]) {
3901 cfg.cls += ' col-' + size + '-' + settings[size];
3905 var inputblock = input;
3907 if (this.before || this.after) {
3910 cls : 'input-group',
3914 inputblock.cn.push({
3916 cls : 'input-group-addon',
3920 inputblock.cn.push(input);
3922 inputblock.cn.push({
3924 cls : 'input-group-addon',
3931 if (align ==='left' && this.fieldLabel.length) {
3932 Roo.log("left and has label");
3938 cls : 'control-label col-sm-' + this.labelWidth,
3939 html : this.fieldLabel
3943 cls : "col-sm-" + (12 - this.labelWidth),
3950 } else if ( this.fieldLabel.length) {
3956 //cls : 'input-group-addon',
3957 html : this.fieldLabel
3967 Roo.log(" no label && no align");
3981 * return the real input element.
3983 inputEl: function ()
3985 return this.el.select('input.form-control',true).first();
3987 setDisabled : function(v)
3989 var i = this.inputEl().dom;
3991 i.removeAttribute('disabled');
3995 i.setAttribute('disabled','true');
3997 initEvents : function()
4000 this.inputEl().on("keydown" , this.fireKey, this);
4001 this.inputEl().on("focus", this.onFocus, this);
4002 this.inputEl().on("blur", this.onBlur, this);
4004 this.inputEl().relayEvent('keyup', this);
4006 // reference to original value for reset
4007 this.originalValue = this.getValue();
4008 //Roo.form.TextField.superclass.initEvents.call(this);
4009 if(this.validationEvent == 'keyup'){
4010 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
4011 this.inputEl().on('keyup', this.filterValidation, this);
4013 else if(this.validationEvent !== false){
4014 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
4017 if(this.selectOnFocus){
4018 this.on("focus", this.preFocus, this);
4021 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
4022 this.inputEl().on("keypress", this.filterKeys, this);
4025 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
4026 this.el.on("click", this.autoSize, this);
4029 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
4030 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
4034 filterValidation : function(e){
4035 if(!e.isNavKeyPress()){
4036 this.validationTask.delay(this.validationDelay);
4040 * Validates the field value
4041 * @return {Boolean} True if the value is valid, else false
4043 validate : function(){
4044 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
4045 if(this.disabled || this.validateValue(this.getRawValue())){
4046 this.clearInvalid();
4054 * Validates a value according to the field's validation rules and marks the field as invalid
4055 * if the validation fails
4056 * @param {Mixed} value The value to validate
4057 * @return {Boolean} True if the value is valid, else false
4059 validateValue : function(value){
4060 if(value.length < 1) { // if it's blank
4061 if(this.allowBlank){
4062 this.clearInvalid();
4065 this.markInvalid(this.blankText);
4069 if(value.length < this.minLength){
4070 this.markInvalid(String.format(this.minLengthText, this.minLength));
4073 if(value.length > this.maxLength){
4074 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
4078 var vt = Roo.form.VTypes;
4079 if(!vt[this.vtype](value, this)){
4080 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
4084 if(typeof this.validator == "function"){
4085 var msg = this.validator(value);
4087 this.markInvalid(msg);
4091 if(this.regex && !this.regex.test(value)){
4092 this.markInvalid(this.regexText);
4101 fireKey : function(e){
4102 //Roo.log('field ' + e.getKey());
4103 if(e.isNavKeyPress()){
4104 this.fireEvent("specialkey", this, e);
4107 focus : function (selectText){
4109 this.inputEl().focus();
4110 if(selectText === true){
4111 this.inputEl().dom.select();
4117 onFocus : function(){
4118 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4119 // this.el.addClass(this.focusClass);
4122 this.hasFocus = true;
4123 this.startValue = this.getValue();
4124 this.fireEvent("focus", this);
4128 beforeBlur : Roo.emptyFn,
4132 onBlur : function(){
4134 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4135 //this.el.removeClass(this.focusClass);
4137 this.hasFocus = false;
4138 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
4141 var v = this.getValue();
4142 if(String(v) !== String(this.startValue)){
4143 this.fireEvent('change', this, v, this.startValue);
4145 this.fireEvent("blur", this);
4149 * Resets the current field value to the originally loaded value and clears any validation messages
4152 this.setValue(this.originalValue);
4153 this.clearInvalid();
4156 * Returns the name of the field
4157 * @return {Mixed} name The name field
4159 getName: function(){
4163 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
4164 * @return {Mixed} value The field value
4166 getValue : function(){
4167 return this.inputEl().getValue();
4170 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
4171 * @return {Mixed} value The field value
4173 getRawValue : function(){
4174 var v = this.inputEl().getValue();
4180 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
4181 * @param {Mixed} value The value to set
4183 setRawValue : function(v){
4184 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4187 selectText : function(start, end){
4188 var v = this.getRawValue();
4190 start = start === undefined ? 0 : start;
4191 end = end === undefined ? v.length : end;
4192 var d = this.inputEl().dom;
4193 if(d.setSelectionRange){
4194 d.setSelectionRange(start, end);
4195 }else if(d.createTextRange){
4196 var range = d.createTextRange();
4197 range.moveStart("character", start);
4198 range.moveEnd("character", v.length-end);
4205 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
4206 * @param {Mixed} value The value to set
4208 setValue : function(v){
4211 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4217 processValue : function(value){
4218 if(this.stripCharsRe){
4219 var newValue = value.replace(this.stripCharsRe, '');
4220 if(newValue !== value){
4221 this.setRawValue(newValue);
4228 preFocus : function(){
4230 if(this.selectOnFocus){
4231 this.inputEl().dom.select();
4234 filterKeys : function(e){
4236 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
4239 var c = e.getCharCode(), cc = String.fromCharCode(c);
4240 if(Roo.isIE && (e.isSpecialKey() || !cc)){
4243 if(!this.maskRe.test(cc)){
4248 * Clear any invalid styles/messages for this field
4250 clearInvalid : function(){
4252 if(!this.el || this.preventMark){ // not rendered
4255 this.el.removeClass(this.invalidClass);
4257 switch(this.msgTarget){
4259 this.el.dom.qtip = '';
4262 this.el.dom.title = '';
4266 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
4271 this.errorIcon.dom.qtip = '';
4272 this.errorIcon.hide();
4273 this.un('resize', this.alignErrorIcon, this);
4277 var t = Roo.getDom(this.msgTarget);
4279 t.style.display = 'none';
4283 this.fireEvent('valid', this);
4286 * Mark this field as invalid
4287 * @param {String} msg The validation message
4289 markInvalid : function(msg){
4290 if(!this.el || this.preventMark){ // not rendered
4293 this.el.addClass(this.invalidClass);
4295 msg = msg || this.invalidText;
4296 switch(this.msgTarget){
4298 this.el.dom.qtip = msg;
4299 this.el.dom.qclass = 'x-form-invalid-tip';
4300 if(Roo.QuickTips){ // fix for floating editors interacting with DND
4301 Roo.QuickTips.enable();
4305 this.el.dom.title = msg;
4309 var elp = this.el.findParent('.x-form-element', 5, true);
4310 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
4311 this.errorEl.setWidth(elp.getWidth(true)-20);
4313 this.errorEl.update(msg);
4314 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
4317 if(!this.errorIcon){
4318 var elp = this.el.findParent('.x-form-element', 5, true);
4319 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
4321 this.alignErrorIcon();
4322 this.errorIcon.dom.qtip = msg;
4323 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
4324 this.errorIcon.show();
4325 this.on('resize', this.alignErrorIcon, this);
4328 var t = Roo.getDom(this.msgTarget);
4330 t.style.display = this.msgDisplay;
4334 this.fireEvent('invalid', this, msg);
4337 SafariOnKeyDown : function(event)
4339 // this is a workaround for a password hang bug on chrome/ webkit.
4341 var isSelectAll = false;
4343 if(this.inputEl().dom.selectionEnd > 0){
4344 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
4346 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
4347 event.preventDefault();
4352 if(isSelectAll){ // backspace and delete key
4354 event.preventDefault();
4355 // this is very hacky as keydown always get's upper case.
4357 var cc = String.fromCharCode(event.getCharCode());
4358 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
4374 * @class Roo.bootstrap.TextArea
4375 * @extends Roo.bootstrap.Input
4376 * Bootstrap TextArea class
4377 * @cfg {Number} cols Specifies the visible width of a text area
4378 * @cfg {Number} rows Specifies the visible number of lines in a text area
4379 * @cfg {Number} readOnly Specifies that a text area should be read-only
4380 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
4381 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
4382 * @cfg {string} html text
4385 * Create a new TextArea
4386 * @param {Object} config The config object
4389 Roo.bootstrap.TextArea = function(config){
4390 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
4394 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
4404 getAutoCreate : function(){
4406 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4417 value : this.value || '',
4418 html: this.html || '',
4419 cls : 'form-control',
4420 placeholder : this.placeholder || ''
4424 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4425 input.maxLength = this.maxLength;
4429 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
4433 input.cols = this.cols;
4436 if (this.readOnly) {
4437 input.readonly = true;
4441 input.name = this.name;
4445 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
4449 ['xs','sm','md','lg'].map(function(size){
4450 if (settings[size]) {
4451 cfg.cls += ' col-' + size + '-' + settings[size];
4455 var inputblock = input;
4457 if (this.before || this.after) {
4460 cls : 'input-group',
4464 inputblock.cn.push({
4466 cls : 'input-group-addon',
4470 inputblock.cn.push(input);
4472 inputblock.cn.push({
4474 cls : 'input-group-addon',
4481 if (align ==='left' && this.fieldLabel.length) {
4482 Roo.log("left and has label");
4488 cls : 'control-label col-sm-' + this.labelWidth,
4489 html : this.fieldLabel
4493 cls : "col-sm-" + (12 - this.labelWidth),
4500 } else if ( this.fieldLabel.length) {
4506 //cls : 'input-group-addon',
4507 html : this.fieldLabel
4517 Roo.log(" no label && no align");
4527 if (this.disabled) {
4528 input.disabled=true;
4535 * return the real textarea element.
4537 inputEl: function ()
4539 return this.el.select('textarea.form-control',true).first();
4547 * trigger field - base class for combo..
4552 * @class Roo.bootstrap.TriggerField
4553 * @extends Roo.bootstrap.Input
4554 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
4555 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
4556 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
4557 * for which you can provide a custom implementation. For example:
4559 var trigger = new Roo.bootstrap.TriggerField();
4560 trigger.onTriggerClick = myTriggerFn;
4561 trigger.applyTo('my-field');
4564 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
4565 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
4566 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
4567 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
4569 * Create a new TriggerField.
4570 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
4571 * to the base TextField)
4573 Roo.bootstrap.TriggerField = function(config){
4574 this.mimicing = false;
4575 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
4578 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
4580 * @cfg {String} triggerClass A CSS class to apply to the trigger
4583 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
4587 /** @cfg {Boolean} grow @hide */
4588 /** @cfg {Number} growMin @hide */
4589 /** @cfg {Number} growMax @hide */
4595 autoSize: Roo.emptyFn,
4602 actionMode : 'wrap',
4606 getAutoCreate : function(){
4608 var parent = this.parent();
4610 var align = this.parentLabelAlign();
4615 cls: 'form-group' //input-group
4622 type : this.inputType,
4623 cls : 'form-control',
4624 autocomplete: 'off',
4625 placeholder : this.placeholder || ''
4629 input.name = this.name;
4632 input.cls += ' input-' + this.size;
4635 cls: 'combobox-container input-group',
4640 cls: 'form-hidden-field'
4645 cls : 'typeahead typeahead-long dropdown-menu',
4646 style : 'display:none'
4650 cls : 'input-group-addon btn dropdown-toggle',
4658 cls: 'combobox-clear',
4675 if (align ==='left' && this.fieldLabel.length) {
4679 Roo.log("left and has label");
4685 cls : 'col-sm-2 control-label',
4686 html : this.fieldLabel
4697 } else if ( this.fieldLabel.length) {
4703 //cls : 'input-group-addon',
4704 html : this.fieldLabel
4714 Roo.log(" no label && no align");
4721 ['xs','sm','md','lg'].map(function(size){
4722 if (settings[size]) {
4723 cfg.cls += ' col-' + size + '-' + settings[size];
4729 if (this.disabled) {
4730 input.disabled=true;
4739 onResize : function(w, h){
4740 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
4741 // if(typeof w == 'number'){
4742 // var x = w - this.trigger.getWidth();
4743 // this.inputEl().setWidth(this.adjustWidth('input', x));
4744 // this.trigger.setStyle('left', x+'px');
4749 adjustSize : Roo.BoxComponent.prototype.adjustSize,
4752 getResizeEl : function(){
4753 return this.inputEl();
4757 getPositionEl : function(){
4758 return this.inputEl();
4762 alignErrorIcon : function(){
4763 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
4767 initEvents : function(){
4769 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
4770 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
4772 this.trigger = this.el.select('span.dropdown-toggle',true).first();
4773 if(this.hideTrigger){
4774 this.trigger.setDisplayed(false);
4776 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
4777 //this.trigger.addClassOnOver('x-form-trigger-over');
4778 //this.trigger.addClassOnClick('x-form-trigger-click');
4781 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
4786 initTrigger : function(){
4791 onDestroy : function(){
4793 this.trigger.removeAllListeners();
4794 // this.trigger.remove();
4797 // this.wrap.remove();
4799 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
4803 onFocus : function(){
4804 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
4807 this.wrap.addClass('x-trigger-wrap-focus');
4808 this.mimicing = true;
4809 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
4810 if(this.monitorTab){
4811 this.el.on("keydown", this.checkTab, this);
4818 checkTab : function(e){
4819 if(e.getKey() == e.TAB){
4825 onBlur : function(){
4830 mimicBlur : function(e, t){
4832 if(!this.wrap.contains(t) && this.validateBlur()){
4839 triggerBlur : function(){
4840 this.mimicing = false;
4841 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
4842 if(this.monitorTab){
4843 this.el.un("keydown", this.checkTab, this);
4845 //this.wrap.removeClass('x-trigger-wrap-focus');
4846 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
4850 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
4851 validateBlur : function(e, t){
4856 onDisable : function(){
4857 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
4859 // this.wrap.addClass('x-item-disabled');
4864 onEnable : function(){
4865 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
4867 // this.el.removeClass('x-item-disabled');
4872 onShow : function(){
4873 var ae = this.getActionEl();
4876 ae.dom.style.display = '';
4877 ae.dom.style.visibility = 'visible';
4883 onHide : function(){
4884 var ae = this.getActionEl();
4885 ae.dom.style.display = 'none';
4889 * The function that should handle the trigger's click event. This method does nothing by default until overridden
4890 * by an implementing function.
4892 * @param {EventObject} e
4894 onTriggerClick : Roo.emptyFn
4898 * Ext JS Library 1.1.1
4899 * Copyright(c) 2006-2007, Ext JS, LLC.
4901 * Originally Released Under LGPL - original licence link has changed is not relivant.
4904 * <script type="text/javascript">
4909 * @class Roo.data.SortTypes
4911 * Defines the default sorting (casting?) comparison functions used when sorting data.
4913 Roo.data.SortTypes = {
4915 * Default sort that does nothing
4916 * @param {Mixed} s The value being converted
4917 * @return {Mixed} The comparison value
4924 * The regular expression used to strip tags
4928 stripTagsRE : /<\/?[^>]+>/gi,
4931 * Strips all HTML tags to sort on text only
4932 * @param {Mixed} s The value being converted
4933 * @return {String} The comparison value
4935 asText : function(s){
4936 return String(s).replace(this.stripTagsRE, "");
4940 * Strips all HTML tags to sort on text only - Case insensitive
4941 * @param {Mixed} s The value being converted
4942 * @return {String} The comparison value
4944 asUCText : function(s){
4945 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4949 * Case insensitive string
4950 * @param {Mixed} s The value being converted
4951 * @return {String} The comparison value
4953 asUCString : function(s) {
4954 return String(s).toUpperCase();
4959 * @param {Mixed} s The value being converted
4960 * @return {Number} The comparison value
4962 asDate : function(s) {
4966 if(s instanceof Date){
4969 return Date.parse(String(s));
4974 * @param {Mixed} s The value being converted
4975 * @return {Float} The comparison value
4977 asFloat : function(s) {
4978 var val = parseFloat(String(s).replace(/,/g, ""));
4979 if(isNaN(val)) val = 0;
4985 * @param {Mixed} s The value being converted
4986 * @return {Number} The comparison value
4988 asInt : function(s) {
4989 var val = parseInt(String(s).replace(/,/g, ""));
4990 if(isNaN(val)) val = 0;
4995 * Ext JS Library 1.1.1
4996 * Copyright(c) 2006-2007, Ext JS, LLC.
4998 * Originally Released Under LGPL - original licence link has changed is not relivant.
5001 * <script type="text/javascript">
5005 * @class Roo.data.Record
5006 * Instances of this class encapsulate both record <em>definition</em> information, and record
5007 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
5008 * to access Records cached in an {@link Roo.data.Store} object.<br>
5010 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
5011 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
5014 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
5016 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
5017 * {@link #create}. The parameters are the same.
5018 * @param {Array} data An associative Array of data values keyed by the field name.
5019 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
5020 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
5021 * not specified an integer id is generated.
5023 Roo.data.Record = function(data, id){
5024 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
5029 * Generate a constructor for a specific record layout.
5030 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
5031 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
5032 * Each field definition object may contain the following properties: <ul>
5033 * <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,
5034 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
5035 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
5036 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
5037 * is being used, then this is a string containing the javascript expression to reference the data relative to
5038 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
5039 * to the data item relative to the record element. If the mapping expression is the same as the field name,
5040 * this may be omitted.</p></li>
5041 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
5042 * <ul><li>auto (Default, implies no conversion)</li>
5047 * <li>date</li></ul></p></li>
5048 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
5049 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
5050 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
5051 * by the Reader into an object that will be stored in the Record. It is passed the
5052 * following parameters:<ul>
5053 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
5055 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
5057 * <br>usage:<br><pre><code>
5058 var TopicRecord = Roo.data.Record.create(
5059 {name: 'title', mapping: 'topic_title'},
5060 {name: 'author', mapping: 'username'},
5061 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
5062 {name: 'lastPost', mapping: 'post_time', type: 'date'},
5063 {name: 'lastPoster', mapping: 'user2'},
5064 {name: 'excerpt', mapping: 'post_text'}
5067 var myNewRecord = new TopicRecord({
5068 title: 'Do my job please',
5071 lastPost: new Date(),
5072 lastPoster: 'Animal',
5073 excerpt: 'No way dude!'
5075 myStore.add(myNewRecord);
5080 Roo.data.Record.create = function(o){
5082 f.superclass.constructor.apply(this, arguments);
5084 Roo.extend(f, Roo.data.Record);
5085 var p = f.prototype;
5086 p.fields = new Roo.util.MixedCollection(false, function(field){
5089 for(var i = 0, len = o.length; i < len; i++){
5090 p.fields.add(new Roo.data.Field(o[i]));
5092 f.getField = function(name){
5093 return p.fields.get(name);
5098 Roo.data.Record.AUTO_ID = 1000;
5099 Roo.data.Record.EDIT = 'edit';
5100 Roo.data.Record.REJECT = 'reject';
5101 Roo.data.Record.COMMIT = 'commit';
5103 Roo.data.Record.prototype = {
5105 * Readonly flag - true if this record has been modified.
5114 join : function(store){
5119 * Set the named field to the specified value.
5120 * @param {String} name The name of the field to set.
5121 * @param {Object} value The value to set the field to.
5123 set : function(name, value){
5124 if(this.data[name] == value){
5131 if(typeof this.modified[name] == 'undefined'){
5132 this.modified[name] = this.data[name];
5134 this.data[name] = value;
5135 if(!this.editing && this.store){
5136 this.store.afterEdit(this);
5141 * Get the value of the named field.
5142 * @param {String} name The name of the field to get the value of.
5143 * @return {Object} The value of the field.
5145 get : function(name){
5146 return this.data[name];
5150 beginEdit : function(){
5151 this.editing = true;
5156 cancelEdit : function(){
5157 this.editing = false;
5158 delete this.modified;
5162 endEdit : function(){
5163 this.editing = false;
5164 if(this.dirty && this.store){
5165 this.store.afterEdit(this);
5170 * Usually called by the {@link Roo.data.Store} which owns the Record.
5171 * Rejects all changes made to the Record since either creation, or the last commit operation.
5172 * Modified fields are reverted to their original values.
5174 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5175 * of reject operations.
5177 reject : function(){
5178 var m = this.modified;
5180 if(typeof m[n] != "function"){
5181 this.data[n] = m[n];
5185 delete this.modified;
5186 this.editing = false;
5188 this.store.afterReject(this);
5193 * Usually called by the {@link Roo.data.Store} which owns the Record.
5194 * Commits all changes made to the Record since either creation, or the last commit operation.
5196 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5197 * of commit operations.
5199 commit : function(){
5201 delete this.modified;
5202 this.editing = false;
5204 this.store.afterCommit(this);
5209 hasError : function(){
5210 return this.error != null;
5214 clearError : function(){
5219 * Creates a copy of this record.
5220 * @param {String} id (optional) A new record id if you don't want to use this record's id
5223 copy : function(newId) {
5224 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
5228 * Ext JS Library 1.1.1
5229 * Copyright(c) 2006-2007, Ext JS, LLC.
5231 * Originally Released Under LGPL - original licence link has changed is not relivant.
5234 * <script type="text/javascript">
5240 * @class Roo.data.Store
5241 * @extends Roo.util.Observable
5242 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
5243 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
5245 * 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
5246 * has no knowledge of the format of the data returned by the Proxy.<br>
5248 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
5249 * instances from the data object. These records are cached and made available through accessor functions.
5251 * Creates a new Store.
5252 * @param {Object} config A config object containing the objects needed for the Store to access data,
5253 * and read the data into Records.
5255 Roo.data.Store = function(config){
5256 this.data = new Roo.util.MixedCollection(false);
5257 this.data.getKey = function(o){
5260 this.baseParams = {};
5267 "multisort" : "_multisort"
5270 if(config && config.data){
5271 this.inlineData = config.data;
5275 Roo.apply(this, config);
5277 if(this.reader){ // reader passed
5278 this.reader = Roo.factory(this.reader, Roo.data);
5279 this.reader.xmodule = this.xmodule || false;
5280 if(!this.recordType){
5281 this.recordType = this.reader.recordType;
5283 if(this.reader.onMetaChange){
5284 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
5288 if(this.recordType){
5289 this.fields = this.recordType.prototype.fields;
5295 * @event datachanged
5296 * Fires when the data cache has changed, and a widget which is using this Store
5297 * as a Record cache should refresh its view.
5298 * @param {Store} this
5303 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
5304 * @param {Store} this
5305 * @param {Object} meta The JSON metadata
5310 * Fires when Records have been added to the Store
5311 * @param {Store} this
5312 * @param {Roo.data.Record[]} records The array of Records added
5313 * @param {Number} index The index at which the record(s) were added
5318 * Fires when a Record has been removed from the Store
5319 * @param {Store} this
5320 * @param {Roo.data.Record} record The Record that was removed
5321 * @param {Number} index The index at which the record was removed
5326 * Fires when a Record has been updated
5327 * @param {Store} this
5328 * @param {Roo.data.Record} record The Record that was updated
5329 * @param {String} operation The update operation being performed. Value may be one of:
5331 Roo.data.Record.EDIT
5332 Roo.data.Record.REJECT
5333 Roo.data.Record.COMMIT
5339 * Fires when the data cache has been cleared.
5340 * @param {Store} this
5345 * Fires before a request is made for a new data object. If the beforeload handler returns false
5346 * the load action will be canceled.
5347 * @param {Store} this
5348 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5352 * @event beforeloadadd
5353 * Fires after a new set of Records has been loaded.
5354 * @param {Store} this
5355 * @param {Roo.data.Record[]} records The Records that were loaded
5356 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5358 beforeloadadd : true,
5361 * Fires after a new set of Records has been loaded, before they are added to the store.
5362 * @param {Store} this
5363 * @param {Roo.data.Record[]} records The Records that were loaded
5364 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5365 * @params {Object} return from reader
5369 * @event loadexception
5370 * Fires if an exception occurs in the Proxy during loading.
5371 * Called with the signature of the Proxy's "loadexception" event.
5372 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
5375 * @param {Object} return from JsonData.reader() - success, totalRecords, records
5376 * @param {Object} load options
5377 * @param {Object} jsonData from your request (normally this contains the Exception)
5379 loadexception : true
5383 this.proxy = Roo.factory(this.proxy, Roo.data);
5384 this.proxy.xmodule = this.xmodule || false;
5385 this.relayEvents(this.proxy, ["loadexception"]);
5387 this.sortToggle = {};
5388 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
5390 Roo.data.Store.superclass.constructor.call(this);
5392 if(this.inlineData){
5393 this.loadData(this.inlineData);
5394 delete this.inlineData;
5398 Roo.extend(Roo.data.Store, Roo.util.Observable, {
5400 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
5401 * without a remote query - used by combo/forms at present.
5405 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
5408 * @cfg {Array} data Inline data to be loaded when the store is initialized.
5411 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
5412 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
5415 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
5416 * on any HTTP request
5419 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
5422 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
5426 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
5427 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
5432 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
5433 * loaded or when a record is removed. (defaults to false).
5435 pruneModifiedRecords : false,
5441 * Add Records to the Store and fires the add event.
5442 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
5444 add : function(records){
5445 records = [].concat(records);
5446 for(var i = 0, len = records.length; i < len; i++){
5447 records[i].join(this);
5449 var index = this.data.length;
5450 this.data.addAll(records);
5451 this.fireEvent("add", this, records, index);
5455 * Remove a Record from the Store and fires the remove event.
5456 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
5458 remove : function(record){
5459 var index = this.data.indexOf(record);
5460 this.data.removeAt(index);
5461 if(this.pruneModifiedRecords){
5462 this.modified.remove(record);
5464 this.fireEvent("remove", this, record, index);
5468 * Remove all Records from the Store and fires the clear event.
5470 removeAll : function(){
5472 if(this.pruneModifiedRecords){
5475 this.fireEvent("clear", this);
5479 * Inserts Records to the Store at the given index and fires the add event.
5480 * @param {Number} index The start index at which to insert the passed Records.
5481 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
5483 insert : function(index, records){
5484 records = [].concat(records);
5485 for(var i = 0, len = records.length; i < len; i++){
5486 this.data.insert(index, records[i]);
5487 records[i].join(this);
5489 this.fireEvent("add", this, records, index);
5493 * Get the index within the cache of the passed Record.
5494 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
5495 * @return {Number} The index of the passed Record. Returns -1 if not found.
5497 indexOf : function(record){
5498 return this.data.indexOf(record);
5502 * Get the index within the cache of the Record with the passed id.
5503 * @param {String} id The id of the Record to find.
5504 * @return {Number} The index of the Record. Returns -1 if not found.
5506 indexOfId : function(id){
5507 return this.data.indexOfKey(id);
5511 * Get the Record with the specified id.
5512 * @param {String} id The id of the Record to find.
5513 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
5515 getById : function(id){
5516 return this.data.key(id);
5520 * Get the Record at the specified index.
5521 * @param {Number} index The index of the Record to find.
5522 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
5524 getAt : function(index){
5525 return this.data.itemAt(index);
5529 * Returns a range of Records between specified indices.
5530 * @param {Number} startIndex (optional) The starting index (defaults to 0)
5531 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
5532 * @return {Roo.data.Record[]} An array of Records
5534 getRange : function(start, end){
5535 return this.data.getRange(start, end);
5539 storeOptions : function(o){
5540 o = Roo.apply({}, o);
5543 this.lastOptions = o;
5547 * Loads the Record cache from the configured Proxy using the configured Reader.
5549 * If using remote paging, then the first load call must specify the <em>start</em>
5550 * and <em>limit</em> properties in the options.params property to establish the initial
5551 * position within the dataset, and the number of Records to cache on each read from the Proxy.
5553 * <strong>It is important to note that for remote data sources, loading is asynchronous,
5554 * and this call will return before the new data has been loaded. Perform any post-processing
5555 * in a callback function, or in a "load" event handler.</strong>
5557 * @param {Object} options An object containing properties which control loading options:<ul>
5558 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
5559 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
5560 * passed the following arguments:<ul>
5561 * <li>r : Roo.data.Record[]</li>
5562 * <li>options: Options object from the load call</li>
5563 * <li>success: Boolean success indicator</li></ul></li>
5564 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
5565 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
5568 load : function(options){
5569 options = options || {};
5570 if(this.fireEvent("beforeload", this, options) !== false){
5571 this.storeOptions(options);
5572 var p = Roo.apply(options.params || {}, this.baseParams);
5573 // if meta was not loaded from remote source.. try requesting it.
5574 if (!this.reader.metaFromRemote) {
5577 if(this.sortInfo && this.remoteSort){
5578 var pn = this.paramNames;
5579 p[pn["sort"]] = this.sortInfo.field;
5580 p[pn["dir"]] = this.sortInfo.direction;
5582 if (this.multiSort) {
5583 var pn = this.paramNames;
5584 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
5587 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5592 * Reloads the Record cache from the configured Proxy using the configured Reader and
5593 * the options from the last load operation performed.
5594 * @param {Object} options (optional) An object containing properties which may override the options
5595 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5596 * the most recently used options are reused).
5598 reload : function(options){
5599 this.load(Roo.applyIf(options||{}, this.lastOptions));
5603 // Called as a callback by the Reader during a load operation.
5604 loadRecords : function(o, options, success){
5605 if(!o || success === false){
5606 if(success !== false){
5607 this.fireEvent("load", this, [], options, o);
5609 if(options.callback){
5610 options.callback.call(options.scope || this, [], options, false);
5614 // if data returned failure - throw an exception.
5615 if (o.success === false) {
5616 // show a message if no listener is registered.
5617 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
5618 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
5620 // loadmask wil be hooked into this..
5621 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
5624 var r = o.records, t = o.totalRecords || r.length;
5626 this.fireEvent("beforeloadadd", this, r, options, o);
5628 if(!options || options.add !== true){
5629 if(this.pruneModifiedRecords){
5632 for(var i = 0, len = r.length; i < len; i++){
5636 this.data = this.snapshot;
5637 delete this.snapshot;
5640 this.data.addAll(r);
5641 this.totalLength = t;
5643 this.fireEvent("datachanged", this);
5645 this.totalLength = Math.max(t, this.data.length+r.length);
5648 this.fireEvent("load", this, r, options, o);
5649 if(options.callback){
5650 options.callback.call(options.scope || this, r, options, true);
5656 * Loads data from a passed data block. A Reader which understands the format of the data
5657 * must have been configured in the constructor.
5658 * @param {Object} data The data block from which to read the Records. The format of the data expected
5659 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5660 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5662 loadData : function(o, append){
5663 var r = this.reader.readRecords(o);
5664 this.loadRecords(r, {add: append}, true);
5668 * Gets the number of cached records.
5670 * <em>If using paging, this may not be the total size of the dataset. If the data object
5671 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5672 * the data set size</em>
5674 getCount : function(){
5675 return this.data.length || 0;
5679 * Gets the total number of records in the dataset as returned by the server.
5681 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5682 * the dataset size</em>
5684 getTotalCount : function(){
5685 return this.totalLength || 0;
5689 * Returns the sort state of the Store as an object with two properties:
5691 field {String} The name of the field by which the Records are sorted
5692 direction {String} The sort order, "ASC" or "DESC"
5695 getSortState : function(){
5696 return this.sortInfo;
5700 applySort : function(){
5701 if(this.sortInfo && !this.remoteSort){
5702 var s = this.sortInfo, f = s.field;
5703 var st = this.fields.get(f).sortType;
5704 var fn = function(r1, r2){
5705 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5706 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5708 this.data.sort(s.direction, fn);
5709 if(this.snapshot && this.snapshot != this.data){
5710 this.snapshot.sort(s.direction, fn);
5716 * Sets the default sort column and order to be used by the next load operation.
5717 * @param {String} fieldName The name of the field to sort by.
5718 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5720 setDefaultSort : function(field, dir){
5721 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5726 * If remote sorting is used, the sort is performed on the server, and the cache is
5727 * reloaded. If local sorting is used, the cache is sorted internally.
5728 * @param {String} fieldName The name of the field to sort by.
5729 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5731 sort : function(fieldName, dir){
5732 var f = this.fields.get(fieldName);
5734 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
5736 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
5737 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5742 this.sortToggle[f.name] = dir;
5743 this.sortInfo = {field: f.name, direction: dir};
5744 if(!this.remoteSort){
5746 this.fireEvent("datachanged", this);
5748 this.load(this.lastOptions);
5753 * Calls the specified function for each of the Records in the cache.
5754 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5755 * Returning <em>false</em> aborts and exits the iteration.
5756 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5758 each : function(fn, scope){
5759 this.data.each(fn, scope);
5763 * Gets all records modified since the last commit. Modified records are persisted across load operations
5764 * (e.g., during paging).
5765 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5767 getModifiedRecords : function(){
5768 return this.modified;
5772 createFilterFn : function(property, value, anyMatch){
5773 if(!value.exec){ // not a regex
5774 value = String(value);
5775 if(value.length == 0){
5778 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5781 return value.test(r.data[property]);
5786 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5787 * @param {String} property A field on your records
5788 * @param {Number} start The record index to start at (defaults to 0)
5789 * @param {Number} end The last record index to include (defaults to length - 1)
5790 * @return {Number} The sum
5792 sum : function(property, start, end){
5793 var rs = this.data.items, v = 0;
5795 end = (end || end === 0) ? end : rs.length-1;
5797 for(var i = start; i <= end; i++){
5798 v += (rs[i].data[property] || 0);
5804 * Filter the records by a specified property.
5805 * @param {String} field A field on your records
5806 * @param {String/RegExp} value Either a string that the field
5807 * should start with or a RegExp to test against the field
5808 * @param {Boolean} anyMatch True to match any part not just the beginning
5810 filter : function(property, value, anyMatch){
5811 var fn = this.createFilterFn(property, value, anyMatch);
5812 return fn ? this.filterBy(fn) : this.clearFilter();
5816 * Filter by a function. The specified function will be called with each
5817 * record in this data source. If the function returns true the record is included,
5818 * otherwise it is filtered.
5819 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5820 * @param {Object} scope (optional) The scope of the function (defaults to this)
5822 filterBy : function(fn, scope){
5823 this.snapshot = this.snapshot || this.data;
5824 this.data = this.queryBy(fn, scope||this);
5825 this.fireEvent("datachanged", this);
5829 * Query the records by a specified property.
5830 * @param {String} field A field on your records
5831 * @param {String/RegExp} value Either a string that the field
5832 * should start with or a RegExp to test against the field
5833 * @param {Boolean} anyMatch True to match any part not just the beginning
5834 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5836 query : function(property, value, anyMatch){
5837 var fn = this.createFilterFn(property, value, anyMatch);
5838 return fn ? this.queryBy(fn) : this.data.clone();
5842 * Query by a function. The specified function will be called with each
5843 * record in this data source. If the function returns true the record is included
5845 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5846 * @param {Object} scope (optional) The scope of the function (defaults to this)
5847 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5849 queryBy : function(fn, scope){
5850 var data = this.snapshot || this.data;
5851 return data.filterBy(fn, scope||this);
5855 * Collects unique values for a particular dataIndex from this store.
5856 * @param {String} dataIndex The property to collect
5857 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5858 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5859 * @return {Array} An array of the unique values
5861 collect : function(dataIndex, allowNull, bypassFilter){
5862 var d = (bypassFilter === true && this.snapshot) ?
5863 this.snapshot.items : this.data.items;
5864 var v, sv, r = [], l = {};
5865 for(var i = 0, len = d.length; i < len; i++){
5866 v = d[i].data[dataIndex];
5868 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5877 * Revert to a view of the Record cache with no filtering applied.
5878 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5880 clearFilter : function(suppressEvent){
5881 if(this.snapshot && this.snapshot != this.data){
5882 this.data = this.snapshot;
5883 delete this.snapshot;
5884 if(suppressEvent !== true){
5885 this.fireEvent("datachanged", this);
5891 afterEdit : function(record){
5892 if(this.modified.indexOf(record) == -1){
5893 this.modified.push(record);
5895 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5899 afterReject : function(record){
5900 this.modified.remove(record);
5901 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5905 afterCommit : function(record){
5906 this.modified.remove(record);
5907 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5911 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5912 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5914 commitChanges : function(){
5915 var m = this.modified.slice(0);
5917 for(var i = 0, len = m.length; i < len; i++){
5923 * Cancel outstanding changes on all changed records.
5925 rejectChanges : function(){
5926 var m = this.modified.slice(0);
5928 for(var i = 0, len = m.length; i < len; i++){
5933 onMetaChange : function(meta, rtype, o){
5934 this.recordType = rtype;
5935 this.fields = rtype.prototype.fields;
5936 delete this.snapshot;
5937 this.sortInfo = meta.sortInfo || this.sortInfo;
5939 this.fireEvent('metachange', this, this.reader.meta);
5943 * Ext JS Library 1.1.1
5944 * Copyright(c) 2006-2007, Ext JS, LLC.
5946 * Originally Released Under LGPL - original licence link has changed is not relivant.
5949 * <script type="text/javascript">
5953 * @class Roo.data.SimpleStore
5954 * @extends Roo.data.Store
5955 * Small helper class to make creating Stores from Array data easier.
5956 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5957 * @cfg {Array} fields An array of field definition objects, or field name strings.
5958 * @cfg {Array} data The multi-dimensional array of data
5960 * @param {Object} config
5962 Roo.data.SimpleStore = function(config){
5963 Roo.data.SimpleStore.superclass.constructor.call(this, {
5965 reader: new Roo.data.ArrayReader({
5968 Roo.data.Record.create(config.fields)
5970 proxy : new Roo.data.MemoryProxy(config.data)
5974 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5976 * Ext JS Library 1.1.1
5977 * Copyright(c) 2006-2007, Ext JS, LLC.
5979 * Originally Released Under LGPL - original licence link has changed is not relivant.
5982 * <script type="text/javascript">
5987 * @extends Roo.data.Store
5988 * @class Roo.data.JsonStore
5989 * Small helper class to make creating Stores for JSON data easier. <br/>
5991 var store = new Roo.data.JsonStore({
5992 url: 'get-images.php',
5994 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5997 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5998 * JsonReader and HttpProxy (unless inline data is provided).</b>
5999 * @cfg {Array} fields An array of field definition objects, or field name strings.
6001 * @param {Object} config
6003 Roo.data.JsonStore = function(c){
6004 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
6005 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
6006 reader: new Roo.data.JsonReader(c, c.fields)
6009 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
6011 * Ext JS Library 1.1.1
6012 * Copyright(c) 2006-2007, Ext JS, LLC.
6014 * Originally Released Under LGPL - original licence link has changed is not relivant.
6017 * <script type="text/javascript">
6021 Roo.data.Field = function(config){
6022 if(typeof config == "string"){
6023 config = {name: config};
6025 Roo.apply(this, config);
6031 var st = Roo.data.SortTypes;
6032 // named sortTypes are supported, here we look them up
6033 if(typeof this.sortType == "string"){
6034 this.sortType = st[this.sortType];
6037 // set default sortType for strings and dates
6041 this.sortType = st.asUCString;
6044 this.sortType = st.asDate;
6047 this.sortType = st.none;
6052 var stripRe = /[\$,%]/g;
6054 // prebuilt conversion function for this field, instead of
6055 // switching every time we're reading a value
6057 var cv, dateFormat = this.dateFormat;
6062 cv = function(v){ return v; };
6065 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
6069 return v !== undefined && v !== null && v !== '' ?
6070 parseInt(String(v).replace(stripRe, ""), 10) : '';
6075 return v !== undefined && v !== null && v !== '' ?
6076 parseFloat(String(v).replace(stripRe, ""), 10) : '';
6081 cv = function(v){ return v === true || v === "true" || v == 1; };
6088 if(v instanceof Date){
6092 if(dateFormat == "timestamp"){
6093 return new Date(v*1000);
6095 return Date.parseDate(v, dateFormat);
6097 var parsed = Date.parse(v);
6098 return parsed ? new Date(parsed) : null;
6107 Roo.data.Field.prototype = {
6115 * Ext JS Library 1.1.1
6116 * Copyright(c) 2006-2007, Ext JS, LLC.
6118 * Originally Released Under LGPL - original licence link has changed is not relivant.
6121 * <script type="text/javascript">
6124 // Base class for reading structured data from a data source. This class is intended to be
6125 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
6128 * @class Roo.data.DataReader
6129 * Base class for reading structured data from a data source. This class is intended to be
6130 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
6133 Roo.data.DataReader = function(meta, recordType){
6137 this.recordType = recordType instanceof Array ?
6138 Roo.data.Record.create(recordType) : recordType;
6141 Roo.data.DataReader.prototype = {
6143 * Create an empty record
6144 * @param {Object} data (optional) - overlay some values
6145 * @return {Roo.data.Record} record created.
6147 newRow : function(d) {
6149 this.recordType.prototype.fields.each(function(c) {
6151 case 'int' : da[c.name] = 0; break;
6152 case 'date' : da[c.name] = new Date(); break;
6153 case 'float' : da[c.name] = 0.0; break;
6154 case 'boolean' : da[c.name] = false; break;
6155 default : da[c.name] = ""; break;
6159 return new this.recordType(Roo.apply(da, d));
6164 * Ext JS Library 1.1.1
6165 * Copyright(c) 2006-2007, Ext JS, LLC.
6167 * Originally Released Under LGPL - original licence link has changed is not relivant.
6170 * <script type="text/javascript">
6174 * @class Roo.data.DataProxy
6175 * @extends Roo.data.Observable
6176 * This class is an abstract base class for implementations which provide retrieval of
6177 * unformatted data objects.<br>
6179 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
6180 * (of the appropriate type which knows how to parse the data object) to provide a block of
6181 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
6183 * Custom implementations must implement the load method as described in
6184 * {@link Roo.data.HttpProxy#load}.
6186 Roo.data.DataProxy = function(){
6190 * Fires before a network request is made to retrieve a data object.
6191 * @param {Object} This DataProxy object.
6192 * @param {Object} params The params parameter to the load function.
6197 * Fires before the load method's callback is called.
6198 * @param {Object} This DataProxy object.
6199 * @param {Object} o The data object.
6200 * @param {Object} arg The callback argument object passed to the load function.
6204 * @event loadexception
6205 * Fires if an Exception occurs during data retrieval.
6206 * @param {Object} This DataProxy object.
6207 * @param {Object} o The data object.
6208 * @param {Object} arg The callback argument object passed to the load function.
6209 * @param {Object} e The Exception.
6211 loadexception : true
6213 Roo.data.DataProxy.superclass.constructor.call(this);
6216 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
6219 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
6223 * Ext JS Library 1.1.1
6224 * Copyright(c) 2006-2007, Ext JS, LLC.
6226 * Originally Released Under LGPL - original licence link has changed is not relivant.
6229 * <script type="text/javascript">
6232 * @class Roo.data.MemoryProxy
6233 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
6234 * to the Reader when its load method is called.
6236 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
6238 Roo.data.MemoryProxy = function(data){
6242 Roo.data.MemoryProxy.superclass.constructor.call(this);
6246 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
6248 * Load data from the requested source (in this case an in-memory
6249 * data object passed to the constructor), read the data object into
6250 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6251 * process that block using the passed callback.
6252 * @param {Object} params This parameter is not used by the MemoryProxy class.
6253 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6254 * object into a block of Roo.data.Records.
6255 * @param {Function} callback The function into which to pass the block of Roo.data.records.
6256 * The function must be passed <ul>
6257 * <li>The Record block object</li>
6258 * <li>The "arg" argument from the load function</li>
6259 * <li>A boolean success indicator</li>
6261 * @param {Object} scope The scope in which to call the callback
6262 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6264 load : function(params, reader, callback, scope, arg){
6265 params = params || {};
6268 result = reader.readRecords(this.data);
6270 this.fireEvent("loadexception", this, arg, null, e);
6271 callback.call(scope, null, arg, false);
6274 callback.call(scope, result, arg, true);
6278 update : function(params, records){
6283 * Ext JS Library 1.1.1
6284 * Copyright(c) 2006-2007, Ext JS, LLC.
6286 * Originally Released Under LGPL - original licence link has changed is not relivant.
6289 * <script type="text/javascript">
6292 * @class Roo.data.HttpProxy
6293 * @extends Roo.data.DataProxy
6294 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
6295 * configured to reference a certain URL.<br><br>
6297 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
6298 * from which the running page was served.<br><br>
6300 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
6302 * Be aware that to enable the browser to parse an XML document, the server must set
6303 * the Content-Type header in the HTTP response to "text/xml".
6305 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
6306 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
6307 * will be used to make the request.
6309 Roo.data.HttpProxy = function(conn){
6310 Roo.data.HttpProxy.superclass.constructor.call(this);
6311 // is conn a conn config or a real conn?
6313 this.useAjax = !conn || !conn.events;
6317 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
6318 // thse are take from connection...
6321 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
6324 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
6325 * extra parameters to each request made by this object. (defaults to undefined)
6328 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
6329 * to each request made by this object. (defaults to undefined)
6332 * @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)
6335 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
6338 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
6344 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
6348 * Return the {@link Roo.data.Connection} object being used by this Proxy.
6349 * @return {Connection} The Connection object. This object may be used to subscribe to events on
6350 * a finer-grained basis than the DataProxy events.
6352 getConnection : function(){
6353 return this.useAjax ? Roo.Ajax : this.conn;
6357 * Load data from the configured {@link Roo.data.Connection}, read the data object into
6358 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
6359 * process that block using the passed callback.
6360 * @param {Object} params An object containing properties which are to be used as HTTP parameters
6361 * for the request to the remote server.
6362 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6363 * object into a block of Roo.data.Records.
6364 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6365 * The function must be passed <ul>
6366 * <li>The Record block object</li>
6367 * <li>The "arg" argument from the load function</li>
6368 * <li>A boolean success indicator</li>
6370 * @param {Object} scope The scope in which to call the callback
6371 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6373 load : function(params, reader, callback, scope, arg){
6374 if(this.fireEvent("beforeload", this, params) !== false){
6376 params : params || {},
6378 callback : callback,
6383 callback : this.loadResponse,
6387 Roo.applyIf(o, this.conn);
6388 if(this.activeRequest){
6389 Roo.Ajax.abort(this.activeRequest);
6391 this.activeRequest = Roo.Ajax.request(o);
6393 this.conn.request(o);
6396 callback.call(scope||this, null, arg, false);
6401 loadResponse : function(o, success, response){
6402 delete this.activeRequest;
6404 this.fireEvent("loadexception", this, o, response);
6405 o.request.callback.call(o.request.scope, null, o.request.arg, false);
6410 result = o.reader.read(response);
6412 this.fireEvent("loadexception", this, o, response, e);
6413 o.request.callback.call(o.request.scope, null, o.request.arg, false);
6417 this.fireEvent("load", this, o, o.request.arg);
6418 o.request.callback.call(o.request.scope, result, o.request.arg, true);
6422 update : function(dataSet){
6427 updateResponse : function(dataSet){
6432 * Ext JS Library 1.1.1
6433 * Copyright(c) 2006-2007, Ext JS, LLC.
6435 * Originally Released Under LGPL - original licence link has changed is not relivant.
6438 * <script type="text/javascript">
6442 * @class Roo.data.ScriptTagProxy
6443 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
6444 * other than the originating domain of the running page.<br><br>
6446 * <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
6447 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
6449 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
6450 * source code that is used as the source inside a <script> tag.<br><br>
6452 * In order for the browser to process the returned data, the server must wrap the data object
6453 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
6454 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
6455 * depending on whether the callback name was passed:
6458 boolean scriptTag = false;
6459 String cb = request.getParameter("callback");
6462 response.setContentType("text/javascript");
6464 response.setContentType("application/x-json");
6466 Writer out = response.getWriter();
6468 out.write(cb + "(");
6470 out.print(dataBlock.toJsonString());
6477 * @param {Object} config A configuration object.
6479 Roo.data.ScriptTagProxy = function(config){
6480 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
6481 Roo.apply(this, config);
6482 this.head = document.getElementsByTagName("head")[0];
6485 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
6487 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
6489 * @cfg {String} url The URL from which to request the data object.
6492 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
6496 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
6497 * the server the name of the callback function set up by the load call to process the returned data object.
6498 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
6499 * javascript output which calls this named function passing the data object as its only parameter.
6501 callbackParam : "callback",
6503 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
6504 * name to the request.
6509 * Load data from the configured URL, read the data object into
6510 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6511 * process that block using the passed callback.
6512 * @param {Object} params An object containing properties which are to be used as HTTP parameters
6513 * for the request to the remote server.
6514 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6515 * object into a block of Roo.data.Records.
6516 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6517 * The function must be passed <ul>
6518 * <li>The Record block object</li>
6519 * <li>The "arg" argument from the load function</li>
6520 * <li>A boolean success indicator</li>
6522 * @param {Object} scope The scope in which to call the callback
6523 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6525 load : function(params, reader, callback, scope, arg){
6526 if(this.fireEvent("beforeload", this, params) !== false){
6528 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
6531 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
6533 url += "&_dc=" + (new Date().getTime());
6535 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
6538 cb : "stcCallback"+transId,
6539 scriptId : "stcScript"+transId,
6543 callback : callback,
6549 window[trans.cb] = function(o){
6550 conn.handleResponse(o, trans);
6553 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
6555 if(this.autoAbort !== false){
6559 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
6561 var script = document.createElement("script");
6562 script.setAttribute("src", url);
6563 script.setAttribute("type", "text/javascript");
6564 script.setAttribute("id", trans.scriptId);
6565 this.head.appendChild(script);
6569 callback.call(scope||this, null, arg, false);
6574 isLoading : function(){
6575 return this.trans ? true : false;
6579 * Abort the current server request.
6582 if(this.isLoading()){
6583 this.destroyTrans(this.trans);
6588 destroyTrans : function(trans, isLoaded){
6589 this.head.removeChild(document.getElementById(trans.scriptId));
6590 clearTimeout(trans.timeoutId);
6592 window[trans.cb] = undefined;
6594 delete window[trans.cb];
6597 // if hasn't been loaded, wait for load to remove it to prevent script error
6598 window[trans.cb] = function(){
6599 window[trans.cb] = undefined;
6601 delete window[trans.cb];
6608 handleResponse : function(o, trans){
6610 this.destroyTrans(trans, true);
6613 result = trans.reader.readRecords(o);
6615 this.fireEvent("loadexception", this, o, trans.arg, e);
6616 trans.callback.call(trans.scope||window, null, trans.arg, false);
6619 this.fireEvent("load", this, o, trans.arg);
6620 trans.callback.call(trans.scope||window, result, trans.arg, true);
6624 handleFailure : function(trans){
6626 this.destroyTrans(trans, false);
6627 this.fireEvent("loadexception", this, null, trans.arg);
6628 trans.callback.call(trans.scope||window, null, trans.arg, false);
6632 * Ext JS Library 1.1.1
6633 * Copyright(c) 2006-2007, Ext JS, LLC.
6635 * Originally Released Under LGPL - original licence link has changed is not relivant.
6638 * <script type="text/javascript">
6642 * @class Roo.data.JsonReader
6643 * @extends Roo.data.DataReader
6644 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6645 * based on mappings in a provided Roo.data.Record constructor.
6647 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6648 * in the reply previously.
6653 var RecordDef = Roo.data.Record.create([
6654 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6655 {name: 'occupation'} // This field will use "occupation" as the mapping.
6657 var myReader = new Roo.data.JsonReader({
6658 totalProperty: "results", // The property which contains the total dataset size (optional)
6659 root: "rows", // The property which contains an Array of row objects
6660 id: "id" // The property within each row object that provides an ID for the record (optional)
6664 * This would consume a JSON file like this:
6666 { 'results': 2, 'rows': [
6667 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6668 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6671 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6672 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6673 * paged from the remote server.
6674 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6675 * @cfg {String} root name of the property which contains the Array of row objects.
6676 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6678 * Create a new JsonReader
6679 * @param {Object} meta Metadata configuration options
6680 * @param {Object} recordType Either an Array of field definition objects,
6681 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6683 Roo.data.JsonReader = function(meta, recordType){
6686 // set some defaults:
6688 totalProperty: 'total',
6689 successProperty : 'success',
6694 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6696 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6699 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6700 * Used by Store query builder to append _requestMeta to params.
6703 metaFromRemote : false,
6705 * This method is only used by a DataProxy which has retrieved data from a remote server.
6706 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6707 * @return {Object} data A data block which is used by an Roo.data.Store object as
6708 * a cache of Roo.data.Records.
6710 read : function(response){
6711 var json = response.responseText;
6713 var o = /* eval:var:o */ eval("("+json+")");
6715 throw {message: "JsonReader.read: Json object not found"};
6721 this.metaFromRemote = true;
6722 this.meta = o.metaData;
6723 this.recordType = Roo.data.Record.create(o.metaData.fields);
6724 this.onMetaChange(this.meta, this.recordType, o);
6726 return this.readRecords(o);
6729 // private function a store will implement
6730 onMetaChange : function(meta, recordType, o){
6737 simpleAccess: function(obj, subsc) {
6744 getJsonAccessor: function(){
6746 return function(expr) {
6748 return(re.test(expr))
6749 ? new Function("obj", "return obj." + expr)
6759 * Create a data block containing Roo.data.Records from an XML document.
6760 * @param {Object} o An object which contains an Array of row objects in the property specified
6761 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6762 * which contains the total size of the dataset.
6763 * @return {Object} data A data block which is used by an Roo.data.Store object as
6764 * a cache of Roo.data.Records.
6766 readRecords : function(o){
6768 * After any data loads, the raw JSON data is available for further custom processing.
6772 var s = this.meta, Record = this.recordType,
6773 f = Record.prototype.fields, fi = f.items, fl = f.length;
6775 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6777 if(s.totalProperty) {
6778 this.getTotal = this.getJsonAccessor(s.totalProperty);
6780 if(s.successProperty) {
6781 this.getSuccess = this.getJsonAccessor(s.successProperty);
6783 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6785 var g = this.getJsonAccessor(s.id);
6786 this.getId = function(rec) {
6788 return (r === undefined || r === "") ? null : r;
6791 this.getId = function(){return null;};
6794 for(var jj = 0; jj < fl; jj++){
6796 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6797 this.ef[jj] = this.getJsonAccessor(map);
6801 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6802 if(s.totalProperty){
6803 var vt = parseInt(this.getTotal(o), 10);
6808 if(s.successProperty){
6809 var vs = this.getSuccess(o);
6810 if(vs === false || vs === 'false'){
6815 for(var i = 0; i < c; i++){
6818 var id = this.getId(n);
6819 for(var j = 0; j < fl; j++){
6821 var v = this.ef[j](n);
6823 Roo.log('missing convert for ' + f.name);
6827 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6829 var record = new Record(values, id);
6831 records[i] = record;
6837 totalRecords : totalRecords
6842 * Ext JS Library 1.1.1
6843 * Copyright(c) 2006-2007, Ext JS, LLC.
6845 * Originally Released Under LGPL - original licence link has changed is not relivant.
6848 * <script type="text/javascript">
6852 * @class Roo.data.ArrayReader
6853 * @extends Roo.data.DataReader
6854 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6855 * Each element of that Array represents a row of data fields. The
6856 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6857 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6861 var RecordDef = Roo.data.Record.create([
6862 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6863 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6865 var myReader = new Roo.data.ArrayReader({
6866 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6870 * This would consume an Array like this:
6872 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6874 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6876 * Create a new JsonReader
6877 * @param {Object} meta Metadata configuration options.
6878 * @param {Object} recordType Either an Array of field definition objects
6879 * as specified to {@link Roo.data.Record#create},
6880 * or an {@link Roo.data.Record} object
6881 * created using {@link Roo.data.Record#create}.
6883 Roo.data.ArrayReader = function(meta, recordType){
6884 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6887 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6889 * Create a data block containing Roo.data.Records from an XML document.
6890 * @param {Object} o An Array of row objects which represents the dataset.
6891 * @return {Object} data A data block which is used by an Roo.data.Store object as
6892 * a cache of Roo.data.Records.
6894 readRecords : function(o){
6895 var sid = this.meta ? this.meta.id : null;
6896 var recordType = this.recordType, fields = recordType.prototype.fields;
6899 for(var i = 0; i < root.length; i++){
6902 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6903 for(var j = 0, jlen = fields.length; j < jlen; j++){
6904 var f = fields.items[j];
6905 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6906 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6910 var record = new recordType(values, id);
6912 records[records.length] = record;
6916 totalRecords : records.length
6925 * @class Roo.bootstrap.ComboBox
6926 * @extends Roo.bootstrap.TriggerField
6927 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
6929 * Create a new ComboBox.
6930 * @param {Object} config Configuration options
6932 Roo.bootstrap.ComboBox = function(config){
6933 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
6937 * Fires when the dropdown list is expanded
6938 * @param {Roo.bootstrap.ComboBox} combo This combo box
6943 * Fires when the dropdown list is collapsed
6944 * @param {Roo.bootstrap.ComboBox} combo This combo box
6948 * @event beforeselect
6949 * Fires before a list item is selected. Return false to cancel the selection.
6950 * @param {Roo.bootstrap.ComboBox} combo This combo box
6951 * @param {Roo.data.Record} record The data record returned from the underlying store
6952 * @param {Number} index The index of the selected item in the dropdown list
6954 'beforeselect' : true,
6957 * Fires when a list item is selected
6958 * @param {Roo.bootstrap.ComboBox} combo This combo box
6959 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
6960 * @param {Number} index The index of the selected item in the dropdown list
6964 * @event beforequery
6965 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
6966 * The event object passed has these properties:
6967 * @param {Roo.bootstrap.ComboBox} combo This combo box
6968 * @param {String} query The query
6969 * @param {Boolean} forceAll true to force "all" query
6970 * @param {Boolean} cancel true to cancel the query
6971 * @param {Object} e The query event object
6973 'beforequery': true,
6976 * Fires when the 'add' icon is pressed (add a listener to enable add button)
6977 * @param {Roo.bootstrap.ComboBox} combo This combo box
6982 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
6983 * @param {Roo.bootstrap.ComboBox} combo This combo box
6984 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
6992 this.selectedIndex = -1;
6993 if(this.mode == 'local'){
6994 if(config.queryDelay === undefined){
6995 this.queryDelay = 10;
6997 if(config.minChars === undefined){
7003 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
7006 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
7007 * rendering into an Roo.Editor, defaults to false)
7010 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
7011 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
7014 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
7017 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
7018 * the dropdown list (defaults to undefined, with no header element)
7022 * @cfg {String/Roo.Template} tpl The template to use to render the output
7026 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
7028 listWidth: undefined,
7030 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
7031 * mode = 'remote' or 'text' if mode = 'local')
7033 displayField: undefined,
7035 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
7036 * mode = 'remote' or 'value' if mode = 'local').
7037 * Note: use of a valueField requires the user make a selection
7038 * in order for a value to be mapped.
7040 valueField: undefined,
7044 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
7045 * field's data value (defaults to the underlying DOM element's name)
7047 hiddenName: undefined,
7049 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
7053 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
7055 selectedClass: 'active',
7058 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
7062 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
7063 * anchor positions (defaults to 'tl-bl')
7065 listAlign: 'tl-bl?',
7067 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
7071 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
7072 * query specified by the allQuery config option (defaults to 'query')
7074 triggerAction: 'query',
7076 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
7077 * (defaults to 4, does not apply if editable = false)
7081 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
7082 * delay (typeAheadDelay) if it matches a known value (defaults to false)
7086 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
7087 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
7091 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
7092 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
7096 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
7097 * when editable = true (defaults to false)
7099 selectOnFocus:false,
7101 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
7103 queryParam: 'query',
7105 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
7106 * when mode = 'remote' (defaults to 'Loading...')
7108 loadingText: 'Loading...',
7110 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
7114 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
7118 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
7119 * traditional select (defaults to true)
7123 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
7127 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
7131 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
7132 * listWidth has a higher value)
7136 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
7137 * allow the user to set arbitrary text into the field (defaults to false)
7139 forceSelection:false,
7141 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
7142 * if typeAhead = true (defaults to 250)
7144 typeAheadDelay : 250,
7146 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
7147 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
7149 valueNotFoundText : undefined,
7151 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
7156 * @cfg {Boolean} disableClear Disable showing of clear button.
7158 disableClear : false,
7160 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
7162 alwaysQuery : false,
7168 // element that contains real text value.. (when hidden is used..)
7171 initEvents: function(){
7174 throw "can not find store for combo";
7176 this.store = Roo.factory(this.store, Roo.data);
7180 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
7183 if(this.hiddenName){
7185 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
7187 this.hiddenField.dom.value =
7188 this.hiddenValue !== undefined ? this.hiddenValue :
7189 this.value !== undefined ? this.value : '';
7191 // prevent input submission
7192 this.el.dom.removeAttribute('name');
7193 this.hiddenField.dom.setAttribute('name', this.hiddenName);
7198 // this.el.dom.setAttribute('autocomplete', 'off');
7201 var cls = 'x-combo-list';
7202 this.list = this.el.select('ul',true).first();
7204 //this.list = new Roo.Layer({
7205 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
7208 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
7209 this.list.setWidth(lw);
7211 this.list.on('mouseover', this.onViewOver, this);
7212 this.list.on('mousemove', this.onViewMove, this);
7215 this.list.swallowEvent('mousewheel');
7216 this.assetHeight = 0;
7219 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
7220 this.assetHeight += this.header.getHeight();
7223 this.innerList = this.list.createChild({cls:cls+'-inner'});
7224 this.innerList.on('mouseover', this.onViewOver, this);
7225 this.innerList.on('mousemove', this.onViewMove, this);
7226 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7228 if(this.allowBlank && !this.pageSize && !this.disableClear){
7229 this.footer = this.list.createChild({cls:cls+'-ft'});
7230 this.pageTb = new Roo.Toolbar(this.footer);
7234 this.footer = this.list.createChild({cls:cls+'-ft'});
7235 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
7236 {pageSize: this.pageSize});
7240 if (this.pageTb && this.allowBlank && !this.disableClear) {
7242 this.pageTb.add(new Roo.Toolbar.Fill(), {
7243 cls: 'x-btn-icon x-btn-clear',
7249 _this.onSelect(false, -1);
7254 this.assetHeight += this.footer.getHeight();
7259 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
7262 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
7263 singleSelect:true, store: this.store, selectedClass: this.selectedClass
7265 //this.view.wrapEl.setDisplayed(false);
7266 this.view.on('click', this.onViewClick, this);
7270 this.store.on('beforeload', this.onBeforeLoad, this);
7271 this.store.on('load', this.onLoad, this);
7272 this.store.on('loadexception', this.onLoadException, this);
7275 this.resizer = new Roo.Resizable(this.list, {
7276 pinned:true, handles:'se'
7278 this.resizer.on('resize', function(r, w, h){
7279 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
7281 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
7282 this.restrictHeight();
7284 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
7288 this.editable = true;
7289 this.setEditable(false);
7294 if (typeof(this.events.add.listeners) != 'undefined') {
7296 this.addicon = this.wrap.createChild(
7297 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
7299 this.addicon.on('click', function(e) {
7300 this.fireEvent('add', this);
7303 if (typeof(this.events.edit.listeners) != 'undefined') {
7305 this.editicon = this.wrap.createChild(
7306 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
7308 this.editicon.setStyle('margin-left', '40px');
7310 this.editicon.on('click', function(e) {
7312 // we fire even if inothing is selected..
7313 this.fireEvent('edit', this, this.lastData );
7320 this.keyNav = new Roo.KeyNav(this.inputEl(), {
7322 this.inKeyMode = true;
7326 "down" : function(e){
7327 if(!this.isExpanded()){
7328 this.onTriggerClick();
7330 this.inKeyMode = true;
7335 "enter" : function(e){
7340 "esc" : function(e){
7344 "tab" : function(e){
7347 if(this.fireEvent("specialkey", this, e)){
7348 this.onViewClick(false);
7356 doRelay : function(foo, bar, hname){
7357 if(hname == 'down' || this.scope.isExpanded()){
7358 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
7367 this.queryDelay = Math.max(this.queryDelay || 10,
7368 this.mode == 'local' ? 10 : 250);
7371 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
7374 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
7376 if(this.editable !== false){
7377 this.inputEl().on("keyup", this.onKeyUp, this);
7379 if(this.forceSelection){
7380 this.on('blur', this.doForce, this);
7384 onDestroy : function(){
7386 this.view.setStore(null);
7387 this.view.el.removeAllListeners();
7388 this.view.el.remove();
7389 this.view.purgeListeners();
7392 this.list.dom.innerHTML = '';
7395 this.store.un('beforeload', this.onBeforeLoad, this);
7396 this.store.un('load', this.onLoad, this);
7397 this.store.un('loadexception', this.onLoadException, this);
7399 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
7403 fireKey : function(e){
7404 if(e.isNavKeyPress() && !this.list.isVisible()){
7405 this.fireEvent("specialkey", this, e);
7410 onResize: function(w, h){
7411 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
7413 // if(typeof w != 'number'){
7414 // // we do not handle it!?!?
7417 // var tw = this.trigger.getWidth();
7418 // // tw += this.addicon ? this.addicon.getWidth() : 0;
7419 // // tw += this.editicon ? this.editicon.getWidth() : 0;
7421 // this.inputEl().setWidth( this.adjustWidth('input', x));
7423 // //this.trigger.setStyle('left', x+'px');
7425 // if(this.list && this.listWidth === undefined){
7426 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
7427 // this.list.setWidth(lw);
7428 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7436 * Allow or prevent the user from directly editing the field text. If false is passed,
7437 * the user will only be able to select from the items defined in the dropdown list. This method
7438 * is the runtime equivalent of setting the 'editable' config option at config time.
7439 * @param {Boolean} value True to allow the user to directly edit the field text
7441 setEditable : function(value){
7442 if(value == this.editable){
7445 this.editable = value;
7447 this.inputEl().dom.setAttribute('readOnly', true);
7448 this.inputEl().on('mousedown', this.onTriggerClick, this);
7449 this.inputEl().addClass('x-combo-noedit');
7451 this.inputEl().dom.setAttribute('readOnly', false);
7452 this.inputEl().un('mousedown', this.onTriggerClick, this);
7453 this.inputEl().removeClass('x-combo-noedit');
7458 onBeforeLoad : function(){
7462 //this.innerList.update(this.loadingText ?
7463 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
7464 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
7466 this.restrictHeight();
7467 this.selectedIndex = -1;
7471 onLoad : function(){
7475 if(this.store.getCount() > 0){
7477 this.restrictHeight();
7478 if(this.lastQuery == this.allQuery){
7480 this.inputEl().dom.select();
7482 if(!this.selectByValue(this.value, true)){
7483 this.select(0, true);
7487 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
7488 this.taTask.delay(this.typeAheadDelay);
7492 this.onEmptyResults();
7497 onLoadException : function()
7500 Roo.log(this.store.reader.jsonData);
7501 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7503 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7509 onTypeAhead : function(){
7510 if(this.store.getCount() > 0){
7511 var r = this.store.getAt(0);
7512 var newValue = r.data[this.displayField];
7513 var len = newValue.length;
7514 var selStart = this.getRawValue().length;
7516 if(selStart != len){
7517 this.setRawValue(newValue);
7518 this.selectText(selStart, newValue.length);
7524 onSelect : function(record, index){
7525 if(this.fireEvent('beforeselect', this, record, index) !== false){
7526 this.setFromData(index > -1 ? record.data : false);
7528 this.fireEvent('select', this, record, index);
7533 * Returns the currently selected field value or empty string if no value is set.
7534 * @return {String} value The selected value
7536 getValue : function(){
7537 if(this.valueField){
7538 return typeof this.value != 'undefined' ? this.value : '';
7540 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
7545 * Clears any text/value currently set in the field
7547 clearValue : function(){
7548 if(this.hiddenField){
7549 this.hiddenField.dom.value = '';
7552 this.setRawValue('');
7553 this.lastSelectionText = '';
7558 * Sets the specified value into the field. If the value finds a match, the corresponding record text
7559 * will be displayed in the field. If the value does not match the data value of an existing item,
7560 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
7561 * Otherwise the field will be blank (although the value will still be set).
7562 * @param {String} value The value to match
7564 setValue : function(v){
7566 if(this.valueField){
7567 var r = this.findRecord(this.valueField, v);
7569 text = r.data[this.displayField];
7570 }else if(this.valueNotFoundText !== undefined){
7571 text = this.valueNotFoundText;
7574 this.lastSelectionText = text;
7575 if(this.hiddenField){
7576 this.hiddenField.dom.value = v;
7578 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
7582 * @property {Object} the last set data for the element
7587 * Sets the value of the field based on a object which is related to the record format for the store.
7588 * @param {Object} value the value to set as. or false on reset?
7590 setFromData : function(o){
7591 var dv = ''; // display value
7592 var vv = ''; // value value..
7594 if (this.displayField) {
7595 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
7597 // this is an error condition!!!
7598 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
7601 if(this.valueField){
7602 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
7604 if(this.hiddenField){
7605 this.hiddenField.dom.value = vv;
7607 this.lastSelectionText = dv;
7608 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7612 // no hidden field.. - we store the value in 'value', but still display
7613 // display field!!!!
7614 this.lastSelectionText = dv;
7615 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7622 // overridden so that last data is reset..
7623 this.setValue(this.originalValue);
7624 this.clearInvalid();
7625 this.lastData = false;
7627 this.view.clearSelections();
7631 findRecord : function(prop, value){
7633 if(this.store.getCount() > 0){
7634 this.store.each(function(r){
7635 if(r.data[prop] == value){
7647 // returns hidden if it's set..
7648 if (!this.rendered) {return ''};
7649 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
7653 onViewMove : function(e, t){
7654 this.inKeyMode = false;
7658 onViewOver : function(e, t){
7659 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
7662 var item = this.view.findItemFromChild(t);
7664 var index = this.view.indexOf(item);
7665 this.select(index, false);
7670 onViewClick : function(doFocus)
7672 var index = this.view.getSelectedIndexes()[0];
7673 var r = this.store.getAt(index);
7675 this.onSelect(r, index);
7677 if(doFocus !== false && !this.blockFocus){
7678 this.inputEl().focus();
7683 restrictHeight : function(){
7684 //this.innerList.dom.style.height = '';
7685 //var inner = this.innerList.dom;
7686 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
7687 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
7688 //this.list.beginUpdate();
7689 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
7690 this.list.alignTo(this.inputEl(), this.listAlign);
7691 //this.list.endUpdate();
7695 onEmptyResults : function(){
7700 * Returns true if the dropdown list is expanded, else false.
7702 isExpanded : function(){
7703 return this.list.isVisible();
7707 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
7708 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7709 * @param {String} value The data value of the item to select
7710 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7711 * selected item if it is not currently in view (defaults to true)
7712 * @return {Boolean} True if the value matched an item in the list, else false
7714 selectByValue : function(v, scrollIntoView){
7715 if(v !== undefined && v !== null){
7716 var r = this.findRecord(this.valueField || this.displayField, v);
7718 this.select(this.store.indexOf(r), scrollIntoView);
7726 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
7727 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7728 * @param {Number} index The zero-based index of the list item to select
7729 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7730 * selected item if it is not currently in view (defaults to true)
7732 select : function(index, scrollIntoView){
7733 this.selectedIndex = index;
7734 this.view.select(index);
7735 if(scrollIntoView !== false){
7736 var el = this.view.getNode(index);
7738 //this.innerList.scrollChildIntoView(el, false);
7745 selectNext : function(){
7746 var ct = this.store.getCount();
7748 if(this.selectedIndex == -1){
7750 }else if(this.selectedIndex < ct-1){
7751 this.select(this.selectedIndex+1);
7757 selectPrev : function(){
7758 var ct = this.store.getCount();
7760 if(this.selectedIndex == -1){
7762 }else if(this.selectedIndex != 0){
7763 this.select(this.selectedIndex-1);
7769 onKeyUp : function(e){
7770 if(this.editable !== false && !e.isSpecialKey()){
7771 this.lastKey = e.getKey();
7772 this.dqTask.delay(this.queryDelay);
7777 validateBlur : function(){
7778 return !this.list || !this.list.isVisible();
7782 initQuery : function(){
7783 this.doQuery(this.getRawValue());
7787 doForce : function(){
7788 if(this.el.dom.value.length > 0){
7790 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
7796 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
7797 * query allowing the query action to be canceled if needed.
7798 * @param {String} query The SQL query to execute
7799 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
7800 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
7801 * saved in the current store (defaults to false)
7803 doQuery : function(q, forceAll){
7804 if(q === undefined || q === null){
7813 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
7817 forceAll = qe.forceAll;
7818 if(forceAll === true || (q.length >= this.minChars)){
7819 if(this.lastQuery != q || this.alwaysQuery){
7821 if(this.mode == 'local'){
7822 this.selectedIndex = -1;
7824 this.store.clearFilter();
7826 this.store.filter(this.displayField, q);
7830 this.store.baseParams[this.queryParam] = q;
7832 params: this.getParams(q)
7837 this.selectedIndex = -1;
7844 getParams : function(q){
7846 //p[this.queryParam] = q;
7849 p.limit = this.pageSize;
7855 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
7857 collapse : function(){
7858 if(!this.isExpanded()){
7862 Roo.get(document).un('mousedown', this.collapseIf, this);
7863 Roo.get(document).un('mousewheel', this.collapseIf, this);
7864 if (!this.editable) {
7865 Roo.get(document).un('keydown', this.listKeyPress, this);
7867 this.fireEvent('collapse', this);
7871 collapseIf : function(e){
7872 if(!e.within(this.el) && !e.within(this.el)){
7878 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
7880 expand : function(){
7882 if(this.isExpanded() || !this.hasFocus){
7885 this.list.alignTo(this.inputEl(), this.listAlign);
7887 Roo.get(document).on('mousedown', this.collapseIf, this);
7888 Roo.get(document).on('mousewheel', this.collapseIf, this);
7889 if (!this.editable) {
7890 Roo.get(document).on('keydown', this.listKeyPress, this);
7893 this.fireEvent('expand', this);
7897 // Implements the default empty TriggerField.onTriggerClick function
7898 onTriggerClick : function()
7900 Roo.log('trigger click');
7905 if(this.isExpanded()){
7907 if (!this.blockFocus) {
7908 this.inputEl().focus();
7912 this.hasFocus = true;
7913 if(this.triggerAction == 'all') {
7914 this.doQuery(this.allQuery, true);
7916 this.doQuery(this.getRawValue());
7918 if (!this.blockFocus) {
7919 this.inputEl().focus();
7923 listKeyPress : function(e)
7925 //Roo.log('listkeypress');
7926 // scroll to first matching element based on key pres..
7927 if (e.isSpecialKey()) {
7930 var k = String.fromCharCode(e.getKey()).toUpperCase();
7933 var csel = this.view.getSelectedNodes();
7934 var cselitem = false;
7936 var ix = this.view.indexOf(csel[0]);
7937 cselitem = this.store.getAt(ix);
7938 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
7944 this.store.each(function(v) {
7946 // start at existing selection.
7947 if (cselitem.id == v.id) {
7953 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
7954 match = this.store.indexOf(v);
7960 if (match === false) {
7961 return true; // no more action?
7964 this.view.select(match);
7965 var sn = Roo.get(this.view.getSelectedNodes()[0])
7966 //sn.scrollIntoView(sn.dom.parentNode, false);
7970 * @cfg {Boolean} grow
7974 * @cfg {Number} growMin
7978 * @cfg {Number} growMax
7987 * Ext JS Library 1.1.1
7988 * Copyright(c) 2006-2007, Ext JS, LLC.
7990 * Originally Released Under LGPL - original licence link has changed is not relivant.
7993 * <script type="text/javascript">
7998 * @extends Roo.util.Observable
7999 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
8000 * This class also supports single and multi selection modes. <br>
8001 * Create a data model bound view:
8003 var store = new Roo.data.Store(...);
8005 var view = new Roo.View({
8007 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
8010 selectedClass: "ydataview-selected",
8014 // listen for node click?
8015 view.on("click", function(vw, index, node, e){
8016 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
8020 dataModel.load("foobar.xml");
8022 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
8024 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
8025 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
8027 * Note: old style constructor is still suported (container, template, config)
8031 * @param {Object} config The config object
8034 Roo.View = function(config, depreciated_tpl, depreciated_config){
8036 if (typeof(depreciated_tpl) == 'undefined') {
8037 // new way.. - universal constructor.
8038 Roo.apply(this, config);
8039 this.el = Roo.get(this.el);
8042 this.el = Roo.get(config);
8043 this.tpl = depreciated_tpl;
8044 Roo.apply(this, depreciated_config);
8046 this.wrapEl = this.el.wrap().wrap();
8047 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
8050 if(typeof(this.tpl) == "string"){
8051 this.tpl = new Roo.Template(this.tpl);
8053 // support xtype ctors..
8054 this.tpl = new Roo.factory(this.tpl, Roo);
8066 * @event beforeclick
8067 * Fires before a click is processed. Returns false to cancel the default action.
8068 * @param {Roo.View} this
8069 * @param {Number} index The index of the target node
8070 * @param {HTMLElement} node The target node
8071 * @param {Roo.EventObject} e The raw event object
8073 "beforeclick" : true,
8076 * Fires when a template node is clicked.
8077 * @param {Roo.View} this
8078 * @param {Number} index The index of the target node
8079 * @param {HTMLElement} node The target node
8080 * @param {Roo.EventObject} e The raw event object
8085 * Fires when a template node is double clicked.
8086 * @param {Roo.View} this
8087 * @param {Number} index The index of the target node
8088 * @param {HTMLElement} node The target node
8089 * @param {Roo.EventObject} e The raw event object
8093 * @event contextmenu
8094 * Fires when a template node is right clicked.
8095 * @param {Roo.View} this
8096 * @param {Number} index The index of the target node
8097 * @param {HTMLElement} node The target node
8098 * @param {Roo.EventObject} e The raw event object
8100 "contextmenu" : true,
8102 * @event selectionchange
8103 * Fires when the selected nodes change.
8104 * @param {Roo.View} this
8105 * @param {Array} selections Array of the selected nodes
8107 "selectionchange" : true,
8110 * @event beforeselect
8111 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
8112 * @param {Roo.View} this
8113 * @param {HTMLElement} node The node to be selected
8114 * @param {Array} selections Array of currently selected nodes
8116 "beforeselect" : true,
8118 * @event preparedata
8119 * Fires on every row to render, to allow you to change the data.
8120 * @param {Roo.View} this
8121 * @param {Object} data to be rendered (change this)
8123 "preparedata" : true
8131 "click": this.onClick,
8132 "dblclick": this.onDblClick,
8133 "contextmenu": this.onContextMenu,
8137 this.selections = [];
8139 this.cmp = new Roo.CompositeElementLite([]);
8141 this.store = Roo.factory(this.store, Roo.data);
8142 this.setStore(this.store, true);
8145 if ( this.footer && this.footer.xtype) {
8147 var fctr = this.wrapEl.appendChild(document.createElement("div"));
8149 this.footer.dataSource = this.store
8150 this.footer.container = fctr;
8151 this.footer = Roo.factory(this.footer, Roo);
8152 fctr.insertFirst(this.el);
8154 // this is a bit insane - as the paging toolbar seems to detach the el..
8155 // dom.parentNode.parentNode.parentNode
8156 // they get detached?
8160 Roo.View.superclass.constructor.call(this);
8165 Roo.extend(Roo.View, Roo.util.Observable, {
8168 * @cfg {Roo.data.Store} store Data store to load data from.
8173 * @cfg {String|Roo.Element} el The container element.
8178 * @cfg {String|Roo.Template} tpl The template used by this View
8182 * @cfg {String} dataName the named area of the template to use as the data area
8183 * Works with domtemplates roo-name="name"
8187 * @cfg {String} selectedClass The css class to add to selected nodes
8189 selectedClass : "x-view-selected",
8191 * @cfg {String} emptyText The empty text to show when nothing is loaded.
8196 * @cfg {String} text to display on mask (default Loading)
8200 * @cfg {Boolean} multiSelect Allow multiple selection
8202 multiSelect : false,
8204 * @cfg {Boolean} singleSelect Allow single selection
8206 singleSelect: false,
8209 * @cfg {Boolean} toggleSelect - selecting
8211 toggleSelect : false,
8214 * Returns the element this view is bound to.
8215 * @return {Roo.Element}
8224 * Refreshes the view. - called by datachanged on the store. - do not call directly.
8226 refresh : function(){
8229 // if we are using something like 'domtemplate', then
8230 // the what gets used is:
8231 // t.applySubtemplate(NAME, data, wrapping data..)
8232 // the outer template then get' applied with
8233 // the store 'extra data'
8234 // and the body get's added to the
8235 // roo-name="data" node?
8236 // <span class='roo-tpl-{name}'></span> ?????
8240 this.clearSelections();
8243 var records = this.store.getRange();
8244 if(records.length < 1) {
8246 // is this valid?? = should it render a template??
8248 this.el.update(this.emptyText);
8252 if (this.dataName) {
8253 this.el.update(t.apply(this.store.meta)); //????
8254 el = this.el.child('.roo-tpl-' + this.dataName);
8257 for(var i = 0, len = records.length; i < len; i++){
8258 var data = this.prepareData(records[i].data, i, records[i]);
8259 this.fireEvent("preparedata", this, data, i, records[i]);
8260 html[html.length] = Roo.util.Format.trim(
8262 t.applySubtemplate(this.dataName, data, this.store.meta) :
8269 el.update(html.join(""));
8270 this.nodes = el.dom.childNodes;
8271 this.updateIndexes(0);
8275 * Function to override to reformat the data that is sent to
8276 * the template for each node.
8277 * DEPRICATED - use the preparedata event handler.
8278 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
8279 * a JSON object for an UpdateManager bound view).
8281 prepareData : function(data, index, record)
8283 this.fireEvent("preparedata", this, data, index, record);
8287 onUpdate : function(ds, record){
8288 this.clearSelections();
8289 var index = this.store.indexOf(record);
8290 var n = this.nodes[index];
8291 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
8292 n.parentNode.removeChild(n);
8293 this.updateIndexes(index, index);
8299 onAdd : function(ds, records, index)
8301 this.clearSelections();
8302 if(this.nodes.length == 0){
8306 var n = this.nodes[index];
8307 for(var i = 0, len = records.length; i < len; i++){
8308 var d = this.prepareData(records[i].data, i, records[i]);
8310 this.tpl.insertBefore(n, d);
8313 this.tpl.append(this.el, d);
8316 this.updateIndexes(index);
8319 onRemove : function(ds, record, index){
8320 this.clearSelections();
8321 var el = this.dataName ?
8322 this.el.child('.roo-tpl-' + this.dataName) :
8324 el.dom.removeChild(this.nodes[index]);
8325 this.updateIndexes(index);
8329 * Refresh an individual node.
8330 * @param {Number} index
8332 refreshNode : function(index){
8333 this.onUpdate(this.store, this.store.getAt(index));
8336 updateIndexes : function(startIndex, endIndex){
8337 var ns = this.nodes;
8338 startIndex = startIndex || 0;
8339 endIndex = endIndex || ns.length - 1;
8340 for(var i = startIndex; i <= endIndex; i++){
8341 ns[i].nodeIndex = i;
8346 * Changes the data store this view uses and refresh the view.
8347 * @param {Store} store
8349 setStore : function(store, initial){
8350 if(!initial && this.store){
8351 this.store.un("datachanged", this.refresh);
8352 this.store.un("add", this.onAdd);
8353 this.store.un("remove", this.onRemove);
8354 this.store.un("update", this.onUpdate);
8355 this.store.un("clear", this.refresh);
8356 this.store.un("beforeload", this.onBeforeLoad);
8357 this.store.un("load", this.onLoad);
8358 this.store.un("loadexception", this.onLoad);
8362 store.on("datachanged", this.refresh, this);
8363 store.on("add", this.onAdd, this);
8364 store.on("remove", this.onRemove, this);
8365 store.on("update", this.onUpdate, this);
8366 store.on("clear", this.refresh, this);
8367 store.on("beforeload", this.onBeforeLoad, this);
8368 store.on("load", this.onLoad, this);
8369 store.on("loadexception", this.onLoad, this);
8377 * onbeforeLoad - masks the loading area.
8380 onBeforeLoad : function()
8383 this.el.mask(this.mask ? this.mask : "Loading" );
8385 onLoad : function ()
8392 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
8393 * @param {HTMLElement} node
8394 * @return {HTMLElement} The template node
8396 findItemFromChild : function(node){
8397 var el = this.dataName ?
8398 this.el.child('.roo-tpl-' + this.dataName,true) :
8401 if(!node || node.parentNode == el){
8404 var p = node.parentNode;
8405 while(p && p != el){
8406 if(p.parentNode == el){
8415 onClick : function(e){
8416 var item = this.findItemFromChild(e.getTarget());
8418 var index = this.indexOf(item);
8419 if(this.onItemClick(item, index, e) !== false){
8420 this.fireEvent("click", this, index, item, e);
8423 this.clearSelections();
8428 onContextMenu : function(e){
8429 var item = this.findItemFromChild(e.getTarget());
8431 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
8436 onDblClick : function(e){
8437 var item = this.findItemFromChild(e.getTarget());
8439 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
8443 onItemClick : function(item, index, e)
8445 if(this.fireEvent("beforeclick", this, index, item, e) === false){
8448 if (this.toggleSelect) {
8449 var m = this.isSelected(item) ? 'unselect' : 'select';
8452 _t[m](item, true, false);
8455 if(this.multiSelect || this.singleSelect){
8456 if(this.multiSelect && e.shiftKey && this.lastSelection){
8457 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
8459 this.select(item, this.multiSelect && e.ctrlKey);
8460 this.lastSelection = item;
8468 * Get the number of selected nodes.
8471 getSelectionCount : function(){
8472 return this.selections.length;
8476 * Get the currently selected nodes.
8477 * @return {Array} An array of HTMLElements
8479 getSelectedNodes : function(){
8480 return this.selections;
8484 * Get the indexes of the selected nodes.
8487 getSelectedIndexes : function(){
8488 var indexes = [], s = this.selections;
8489 for(var i = 0, len = s.length; i < len; i++){
8490 indexes.push(s[i].nodeIndex);
8496 * Clear all selections
8497 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
8499 clearSelections : function(suppressEvent){
8500 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
8501 this.cmp.elements = this.selections;
8502 this.cmp.removeClass(this.selectedClass);
8503 this.selections = [];
8505 this.fireEvent("selectionchange", this, this.selections);
8511 * Returns true if the passed node is selected
8512 * @param {HTMLElement/Number} node The node or node index
8515 isSelected : function(node){
8516 var s = this.selections;
8520 node = this.getNode(node);
8521 return s.indexOf(node) !== -1;
8526 * @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
8527 * @param {Boolean} keepExisting (optional) true to keep existing selections
8528 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8530 select : function(nodeInfo, keepExisting, suppressEvent){
8531 if(nodeInfo instanceof Array){
8533 this.clearSelections(true);
8535 for(var i = 0, len = nodeInfo.length; i < len; i++){
8536 this.select(nodeInfo[i], true, true);
8540 var node = this.getNode(nodeInfo);
8541 if(!node || this.isSelected(node)){
8542 return; // already selected.
8545 this.clearSelections(true);
8547 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
8548 Roo.fly(node).addClass(this.selectedClass);
8549 this.selections.push(node);
8551 this.fireEvent("selectionchange", this, this.selections);
8559 * @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
8560 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
8561 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8563 unselect : function(nodeInfo, keepExisting, suppressEvent)
8565 if(nodeInfo instanceof Array){
8566 Roo.each(this.selections, function(s) {
8567 this.unselect(s, nodeInfo);
8571 var node = this.getNode(nodeInfo);
8572 if(!node || !this.isSelected(node)){
8573 Roo.log("not selected");
8574 return; // not selected.
8578 Roo.each(this.selections, function(s) {
8580 Roo.fly(node).removeClass(this.selectedClass);
8587 this.selections= ns;
8588 this.fireEvent("selectionchange", this, this.selections);
8592 * Gets a template node.
8593 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8594 * @return {HTMLElement} The node or null if it wasn't found
8596 getNode : function(nodeInfo){
8597 if(typeof nodeInfo == "string"){
8598 return document.getElementById(nodeInfo);
8599 }else if(typeof nodeInfo == "number"){
8600 return this.nodes[nodeInfo];
8606 * Gets a range template nodes.
8607 * @param {Number} startIndex
8608 * @param {Number} endIndex
8609 * @return {Array} An array of nodes
8611 getNodes : function(start, end){
8612 var ns = this.nodes;
8614 end = typeof end == "undefined" ? ns.length - 1 : end;
8617 for(var i = start; i <= end; i++){
8621 for(var i = start; i >= end; i--){
8629 * Finds the index of the passed node
8630 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8631 * @return {Number} The index of the node or -1
8633 indexOf : function(node){
8634 node = this.getNode(node);
8635 if(typeof node.nodeIndex == "number"){
8636 return node.nodeIndex;
8638 var ns = this.nodes;
8639 for(var i = 0, len = ns.length; i < len; i++){
8650 * based on jquery fullcalendar
8654 Roo.bootstrap = Roo.bootstrap || {};
8656 * @class Roo.bootstrap.Calendar
8657 * @extends Roo.bootstrap.Component
8658 * Bootstrap Calendar class
8661 * Create a new Container
8662 * @param {Object} config The config object
8667 Roo.bootstrap.Calendar = function(config){
8668 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
8672 * Fires when a date is selected
8673 * @param {DatePicker} this
8674 * @param {Date} date The selected date
8678 * @event monthchange
8679 * Fires when the displayed month changes
8680 * @param {DatePicker} this
8681 * @param {Date} date The selected month
8683 'monthchange': true,
8686 * Fires when mouse over an event
8687 * @param {Calendar} this
8688 * @param {event} Event
8693 * Fires when the mouse leaves an
8694 * @param {Calendar} this
8700 * Fires when the mouse click an
8701 * @param {Calendar} this
8710 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
8713 * @cfg {Number} startDay
8714 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
8718 getAutoCreate : function(){
8721 var fc_button = function(name, corner, style, content ) {
8722 return Roo.apply({},{
8724 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
8726 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
8729 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
8737 style : 'width:100%',
8744 cls : 'fc-header-left',
8746 fc_button('prev', 'left', 'arrow', '‹' ),
8747 fc_button('next', 'right', 'arrow', '›' ),
8748 { tag: 'span', cls: 'fc-header-space' },
8749 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
8757 cls : 'fc-header-center',
8761 cls: 'fc-header-title',
8764 html : 'month / year'
8772 cls : 'fc-header-right',
8774 /* fc_button('month', 'left', '', 'month' ),
8775 fc_button('week', '', '', 'week' ),
8776 fc_button('day', 'right', '', 'day' )
8788 var cal_heads = function() {
8790 // fixme - handle this.
8792 for (var i =0; i < Date.dayNames.length; i++) {
8793 var d = Date.dayNames[i];
8796 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
8797 html : d.substring(0,3)
8801 ret[0].cls += ' fc-first';
8802 ret[6].cls += ' fc-last';
8805 var cal_cell = function(n) {
8808 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
8813 cls: 'fc-day-number',
8817 cls: 'fc-day-content',
8821 style: 'position: relative;' // height: 17px;
8833 var cal_rows = function() {
8836 for (var r = 0; r < 6; r++) {
8843 for (var i =0; i < Date.dayNames.length; i++) {
8844 var d = Date.dayNames[i];
8845 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
8848 row.cn[0].cls+=' fc-first';
8849 row.cn[0].cn[0].style = 'min-height:90px';
8850 row.cn[6].cls+=' fc-last';
8854 ret[0].cls += ' fc-first';
8855 ret[4].cls += ' fc-prev-last';
8856 ret[5].cls += ' fc-last';
8863 cls: 'fc-border-separate',
8864 style : 'width:100%',
8872 cls : 'fc-first fc-last',
8891 style : "position: relative;",
8894 cls : 'fc-view fc-view-month fc-grid',
8895 style : 'position: relative',
8896 unselectable : 'on',
8899 cls : 'fc-event-container',
8900 style : 'position:absolute;z-index:8;top:0;left:0;'
8918 initEvents : function()
8921 throw "can not find store for calendar";
8924 this.maskEl = Roo.DomHelper.append(this.el, {tag: "div", cls:"x-dlg-mask"}, true);
8925 this.maskEl.enableDisplayMode("block");
8928 this.store = Roo.factory(this.store, Roo.data);
8929 this.store.on('load', this.onLoad, this);
8933 this.cells = this.el.select('.fc-day',true);
8934 //Roo.log(this.cells);
8935 this.textNodes = this.el.query('.fc-day-number');
8936 this.cells.addClassOnOver('fc-state-hover');
8938 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
8939 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
8940 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
8941 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
8943 this.on('monthchange', this.onMonthChange, this);
8945 this.update(new Date().clearTime());
8948 resize : function() {
8949 var sz = this.el.getSize();
8951 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
8952 this.el.select('.fc-day-content div',true).setHeight(34);
8957 showPrevMonth : function(e){
8958 this.update(this.activeDate.add("mo", -1));
8960 showToday : function(e){
8961 this.update(new Date().clearTime());
8964 showNextMonth : function(e){
8965 this.update(this.activeDate.add("mo", 1));
8969 showPrevYear : function(){
8970 this.update(this.activeDate.add("y", -1));
8974 showNextYear : function(){
8975 this.update(this.activeDate.add("y", 1));
8980 update : function(date)
8982 var vd = this.activeDate;
8983 this.activeDate = date;
8984 // if(vd && this.el){
8985 // var t = date.getTime();
8986 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
8987 // Roo.log('using add remove');
8989 // this.fireEvent('monthchange', this, date);
8991 // this.cells.removeClass("fc-state-highlight");
8992 // this.cells.each(function(c){
8993 // if(c.dateValue == t){
8994 // c.addClass("fc-state-highlight");
8995 // setTimeout(function(){
8996 // try{c.dom.firstChild.focus();}catch(e){}
9006 var days = date.getDaysInMonth();
9008 var firstOfMonth = date.getFirstDateOfMonth();
9009 var startingPos = firstOfMonth.getDay()-this.startDay;
9011 if(startingPos < this.startDay){
9015 var pm = date.add(Date.MONTH, -1);
9016 var prevStart = pm.getDaysInMonth()-startingPos;
9018 this.cells = this.el.select('.fc-day',true);
9019 this.textNodes = this.el.query('.fc-day-number');
9020 this.cells.addClassOnOver('fc-state-hover');
9022 var cells = this.cells.elements;
9023 var textEls = this.textNodes;
9025 Roo.each(cells, function(cell){
9026 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
9029 days += startingPos;
9031 // convert everything to numbers so it's fast
9033 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
9036 //Roo.log(prevStart);
9038 var today = new Date().clearTime().getTime();
9039 var sel = date.clearTime().getTime();
9040 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
9041 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
9042 var ddMatch = this.disabledDatesRE;
9043 var ddText = this.disabledDatesText;
9044 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
9045 var ddaysText = this.disabledDaysText;
9046 var format = this.format;
9048 var setCellClass = function(cal, cell){
9050 //Roo.log('set Cell Class');
9052 var t = d.getTime();
9058 cell.className += " fc-today";
9059 cell.className += " fc-state-highlight";
9060 cell.title = cal.todayText;
9063 // disable highlight in other month..
9064 //cell.className += " fc-state-highlight";
9069 cell.className = " fc-state-disabled";
9070 cell.title = cal.minText;
9074 cell.className = " fc-state-disabled";
9075 cell.title = cal.maxText;
9079 if(ddays.indexOf(d.getDay()) != -1){
9080 cell.title = ddaysText;
9081 cell.className = " fc-state-disabled";
9084 if(ddMatch && format){
9085 var fvalue = d.dateFormat(format);
9086 if(ddMatch.test(fvalue)){
9087 cell.title = ddText.replace("%0", fvalue);
9088 cell.className = " fc-state-disabled";
9092 if (!cell.initialClassName) {
9093 cell.initialClassName = cell.dom.className;
9096 cell.dom.className = cell.initialClassName + ' ' + cell.className;
9101 for(; i < startingPos; i++) {
9102 textEls[i].innerHTML = (++prevStart);
9103 d.setDate(d.getDate()+1);
9105 cells[i].className = "fc-past fc-other-month";
9106 setCellClass(this, cells[i]);
9111 for(; i < days; i++){
9112 intDay = i - startingPos + 1;
9113 textEls[i].innerHTML = (intDay);
9114 d.setDate(d.getDate()+1);
9116 cells[i].className = ''; // "x-date-active";
9117 setCellClass(this, cells[i]);
9121 for(; i < 42; i++) {
9122 textEls[i].innerHTML = (++extraDays);
9123 d.setDate(d.getDate()+1);
9125 cells[i].className = "fc-future fc-other-month";
9126 setCellClass(this, cells[i]);
9129 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
9131 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
9133 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
9134 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
9137 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
9138 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
9141 this.fireEvent('monthchange', this, date);
9145 if(!this.internalRender){
9146 var main = this.el.dom.firstChild;
9147 var w = main.offsetWidth;
9148 this.el.setWidth(w + this.el.getBorderWidth("lr"));
9149 Roo.fly(main).setWidth(w);
9150 this.internalRender = true;
9151 // opera does not respect the auto grow header center column
9152 // then, after it gets a width opera refuses to recalculate
9153 // without a second pass
9154 if(Roo.isOpera && !this.secondPass){
9155 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
9156 this.secondPass = true;
9157 this.update.defer(10, this, [date]);
9164 findCell : function(dt) {
9165 dt = dt.clearTime().getTime();
9167 this.cells.each(function(c){
9168 //Roo.log("check " +c.dateValue + '?=' + dt);
9169 if(c.dateValue == dt){
9179 findCells : function(ev) {
9180 var s = ev.start.clone().clearTime().getTime();
9182 var e= ev.end.clone().clearTime().getTime();
9185 this.cells.each(function(c){
9186 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
9188 if(c.dateValue > e){
9191 if(c.dateValue < s){
9200 findBestRow: function(cells)
9204 for (var i =0 ; i < cells.length;i++) {
9205 ret = Math.max(cells[i].rows || 0,ret);
9212 addItem : function(ev)
9214 // look for vertical location slot in
9215 var cells = this.findCells(ev);
9217 ev.row = this.findBestRow(cells);
9219 // work out the location.
9223 for(var i =0; i < cells.length; i++) {
9231 if (crow.start.getY() == cells[i].getY()) {
9233 crow.end = cells[i];
9249 for (var i = 0; i < cells.length;i++) {
9250 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
9254 this.calevents.push(ev);
9257 clearEvents: function() {
9259 if(!this.calevents){
9263 Roo.each(this.cells.elements, function(c){
9267 Roo.each(this.calevents, function(e) {
9268 Roo.each(e.els, function(el) {
9269 el.un('mouseenter' ,this.onEventEnter, this);
9270 el.un('mouseleave' ,this.onEventLeave, this);
9277 renderEvents: function()
9279 // first make sure there is enough space..
9281 this.cells.each(function(c) {
9283 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
9286 for (var e = 0; e < this.calevents.length; e++) {
9287 var ev = this.calevents[e];
9288 var cells = ev.cells;
9291 for(var i =0; i < rows.length; i++) {
9294 // how many rows should it span..
9297 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
9298 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
9300 unselectable : "on",
9303 cls: 'fc-event-inner',
9307 cls: 'fc-event-time',
9308 html : cells.length > 1 ? '' : ev.time
9312 cls: 'fc-event-title',
9313 html : String.format('{0}', ev.title)
9320 cls: 'ui-resizable-handle ui-resizable-e',
9321 html : '  '
9327 cfg.cls += ' fc-event-start';
9329 if ((i+1) == rows.length) {
9330 cfg.cls += ' fc-event-end';
9333 var ctr = this.el.select('.fc-event-container',true).first();
9334 var cg = ctr.createChild(cfg);
9336 cg.on('mouseenter' ,this.onEventEnter, this, ev);
9337 cg.on('mouseleave' ,this.onEventLeave, this, ev);
9338 cg.on('click', this.onEventClick, this, ev);
9342 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
9343 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
9345 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
9346 cg.setWidth(ebox.right - sbox.x -2);
9354 onEventEnter: function (e, el,event,d) {
9355 this.fireEvent('evententer', this, el, event);
9358 onEventLeave: function (e, el,event,d) {
9359 this.fireEvent('eventleave', this, el, event);
9362 onEventClick: function (e, el,event,d) {
9363 this.fireEvent('eventclick', this, el, event);
9366 onMonthChange: function () {
9376 this.calevents = [];
9378 if(this.store.getCount() > 0){
9379 this.store.data.each(function(d){
9382 start: new Date(d.data.start_dt),
9383 end : new Date(d.data.end_dt),
9384 time : d.data.start_time,
9385 title : d.data.title,
9386 description : d.data.description,
9387 venue : d.data.venue
9392 this.renderEvents();
9397 var size = this.el.getViewSize();
9398 var xy = this.el.getXY();
9400 this.maskEl.setSize(size.width, size.height);
9401 this.maskEl.setXY(xy);
9415 * @class Roo.bootstrap.Popover
9416 * @extends Roo.bootstrap.Component
9417 * Bootstrap Popover class
9418 * @cfg {String} html contents of the popover (or false to use children..)
9419 * @cfg {String} title of popover (or false to hide)
9420 * @cfg {String} placement how it is placed
9421 * @cfg {String} trigger click || hover (or false to trigger manually)
9422 * @cfg {String} over what (parent or false to trigger manually.)
9425 * Create a new Popover
9426 * @param {Object} config The config object
9429 Roo.bootstrap.Popover = function(config){
9430 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
9433 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
9435 title: 'Fill in a title',
9438 placement : 'right',
9439 trigger : 'hover', // hover
9443 can_build_overlaid : false,
9445 getChildContainer : function()
9447 return this.el.select('.popover-content',true).first();
9450 getAutoCreate : function(){
9451 Roo.log('make popover?');
9453 cls : 'popover roo-dynamic',
9454 style: 'display:block',
9460 cls : 'popover-inner',
9464 cls: 'popover-title',
9468 cls : 'popover-content',
9479 setTitle: function(str)
9481 this.el.select('.popover-title',true).first().dom.innerHTML = str;
9483 setContent: function(str)
9485 this.el.select('.popover-content',true).first().dom.innerHTML = str;
9487 // as it get's added to the bottom of the page.
9488 onRender : function(ct, position)
9490 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
9492 var cfg = Roo.apply({}, this.getAutoCreate());
9496 cfg.cls += ' ' + this.cls;
9499 cfg.style = this.style;
9501 Roo.log("adding to ")
9502 this.el = Roo.get(document.body).createChild(cfg, position);
9508 initEvents : function()
9510 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
9511 this.el.enableDisplayMode('block');
9513 if (this.over === false) {
9516 if (this.triggers === false) {
9519 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9520 var triggers = this.trigger ? this.trigger.split(' ') : [];
9521 Roo.each(triggers, function(trigger) {
9523 if (trigger == 'click') {
9524 on_el.on('click', this.toggle, this);
9525 } else if (trigger != 'manual') {
9526 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
9527 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
9529 on_el.on(eventIn ,this.enter, this);
9530 on_el.on(eventOut, this.leave, this);
9541 toggle : function () {
9542 this.hoverState == 'in' ? this.leave() : this.enter();
9545 enter : function () {
9548 clearTimeout(this.timeout);
9550 this.hoverState = 'in'
9552 if (!this.delay || !this.delay.show) {
9557 this.timeout = setTimeout(function () {
9558 if (_t.hoverState == 'in') {
9563 leave : function() {
9564 clearTimeout(this.timeout);
9566 this.hoverState = 'out'
9568 if (!this.delay || !this.delay.hide) {
9573 this.timeout = setTimeout(function () {
9574 if (_t.hoverState == 'out') {
9580 show : function (on_el)
9583 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9586 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
9587 if (this.html !== false) {
9588 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
9590 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
9591 if (!this.title.length) {
9592 this.el.select('.popover-title',true).hide();
9595 var placement = typeof this.placement == 'function' ?
9596 this.placement.call(this, this.el, on_el) :
9599 var autoToken = /\s?auto?\s?/i;
9600 var autoPlace = autoToken.test(placement);
9602 placement = placement.replace(autoToken, '') || 'top';
9606 //this.el.setXY([0,0]);
9608 this.el.dom.style.display='block';
9609 this.el.addClass(placement);
9611 //this.el.appendTo(on_el);
9613 var p = this.getPosition();
9614 var box = this.el.getBox();
9619 var align = Roo.bootstrap.Popover.alignment[placement]
9620 this.el.alignTo(on_el, align[0],align[1]);
9621 //var arrow = this.el.select('.arrow',true).first();
9622 //arrow.set(align[2],
9624 this.el.addClass('in');
9625 this.hoverState = null;
9627 if (this.el.hasClass('fade')) {
9634 this.el.setXY([0,0]);
9635 this.el.removeClass('in');
9642 Roo.bootstrap.Popover.alignment = {
9643 'left' : ['r-l', [-10,0], 'right'],
9644 'right' : ['l-r', [10,0], 'left'],
9645 'bottom' : ['t-b', [0,10], 'top'],
9646 'top' : [ 'b-t', [0,-10], 'bottom']
9657 * @class Roo.bootstrap.Progress
9658 * @extends Roo.bootstrap.Component
9659 * Bootstrap Progress class
9660 * @cfg {Boolean} striped striped of the progress bar
9661 * @cfg {Boolean} active animated of the progress bar
9665 * Create a new Progress
9666 * @param {Object} config The config object
9669 Roo.bootstrap.Progress = function(config){
9670 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
9673 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
9678 getAutoCreate : function(){
9686 cfg.cls += ' progress-striped';
9690 cfg.cls += ' active';
9709 * @class Roo.bootstrap.ProgressBar
9710 * @extends Roo.bootstrap.Component
9711 * Bootstrap ProgressBar class
9712 * @cfg {Number} aria_valuenow aria-value now
9713 * @cfg {Number} aria_valuemin aria-value min
9714 * @cfg {Number} aria_valuemax aria-value max
9715 * @cfg {String} label label for the progress bar
9716 * @cfg {String} panel (success | info | warning | danger )
9717 * @cfg {String} role role of the progress bar
9718 * @cfg {String} sr_only text
9722 * Create a new ProgressBar
9723 * @param {Object} config The config object
9726 Roo.bootstrap.ProgressBar = function(config){
9727 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
9730 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
9734 aria_valuemax : 100,
9740 getAutoCreate : function()
9745 cls: 'progress-bar',
9746 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
9758 cfg.role = this.role;
9761 if(this.aria_valuenow){
9762 cfg['aria-valuenow'] = this.aria_valuenow;
9765 if(this.aria_valuemin){
9766 cfg['aria-valuemin'] = this.aria_valuemin;
9769 if(this.aria_valuemax){
9770 cfg['aria-valuemax'] = this.aria_valuemax;
9773 if(this.label && !this.sr_only){
9774 cfg.html = this.label;
9778 cfg.cls += ' progress-bar-' + this.panel;
9784 update : function(aria_valuenow)
9786 this.aria_valuenow = aria_valuenow;
9788 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
9803 * @class Roo.bootstrap.TabPanel
9804 * @extends Roo.bootstrap.Component
9805 * Bootstrap TabPanel class
9806 * @cfg {Boolean} active panel active
9807 * @cfg {String} html panel content
9808 * @cfg {String} tabId tab relate id
9812 * Create a new TabPanel
9813 * @param {Object} config The config object
9816 Roo.bootstrap.TabPanel = function(config){
9817 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
9820 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
9826 getAutoCreate : function(){
9830 html: this.html || ''
9834 cfg.cls += ' active';
9838 cfg.tabId = this.tabId;
9856 * @class Roo.bootstrap.DateField
9857 * @extends Roo.bootstrap.Input
9858 * Bootstrap DateField class
9859 * @cfg {Number} weekStart default 0
9860 * @cfg {Number} weekStart default 0
9861 * @cfg {Number} viewMode default empty, (months|years)
9862 * @cfg {Number} minViewMode default empty, (months|years)
9863 * @cfg {Number} startDate default -Infinity
9864 * @cfg {Number} endDate default Infinity
9865 * @cfg {Boolean} todayHighlight default false
9866 * @cfg {Boolean} todayBtn default false
9867 * @cfg {Boolean} calendarWeeks default false
9868 * @cfg {Object} daysOfWeekDisabled default empty
9870 * @cfg {Boolean} keyboardNavigation default true
9871 * @cfg {String} language default en
9874 * Create a new DateField
9875 * @param {Object} config The config object
9878 Roo.bootstrap.DateField = function(config){
9879 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
9882 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
9885 * @cfg {String} format
9886 * The default date format string which can be overriden for localization support. The format must be
9887 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
9891 * @cfg {String} altFormats
9892 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
9893 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
9895 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
9903 todayHighlight : false,
9909 keyboardNavigation: true,
9911 calendarWeeks: false,
9913 startDate: -Infinity,
9917 daysOfWeekDisabled: [],
9923 return new Date(Date.UTC.apply(Date, arguments));
9926 UTCToday: function()
9928 var today = new Date();
9929 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
9932 getDate: function() {
9933 var d = this.getUTCDate();
9934 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
9937 getUTCDate: function() {
9941 setDate: function(d) {
9942 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
9945 setUTCDate: function(d) {
9947 this.setValue(this.formatDate(this.date));
9950 onRender: function(ct, position)
9953 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
9955 this.language = this.language || 'en';
9956 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
9957 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
9959 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
9960 this.format = this.format || 'm/d/y';
9961 this.isInline = false;
9962 this.isInput = true;
9963 this.component = this.el.select('.add-on', true).first() || false;
9964 this.component = (this.component && this.component.length === 0) ? false : this.component;
9965 this.hasInput = this.component && this.inputEL().length;
9967 if (typeof(this.minViewMode === 'string')) {
9968 switch (this.minViewMode) {
9970 this.minViewMode = 1;
9973 this.minViewMode = 2;
9976 this.minViewMode = 0;
9981 if (typeof(this.viewMode === 'string')) {
9982 switch (this.viewMode) {
9995 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
9997 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
9999 this.picker().on('mousedown', this.onMousedown, this);
10000 this.picker().on('click', this.onClick, this);
10002 this.picker().addClass('datepicker-dropdown');
10004 this.startViewMode = this.viewMode;
10007 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
10008 if(!this.calendarWeeks){
10013 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
10014 v.attr('colspan', function(i, val){
10015 return parseInt(val) + 1;
10020 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
10022 this.setStartDate(this.startDate);
10023 this.setEndDate(this.endDate);
10025 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
10032 if(this.isInline) {
10037 picker : function()
10039 return this.el.select('.datepicker', true).first();
10042 fillDow: function()
10044 var dowCnt = this.weekStart;
10053 if(this.calendarWeeks){
10061 while (dowCnt < this.weekStart + 7) {
10065 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
10069 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
10072 fillMonths: function()
10075 var months = this.picker().select('>.datepicker-months td', true).first();
10077 months.dom.innerHTML = '';
10083 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
10086 months.createChild(month);
10091 update: function(){
10093 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
10095 if (this.date < this.startDate) {
10096 this.viewDate = new Date(this.startDate);
10097 } else if (this.date > this.endDate) {
10098 this.viewDate = new Date(this.endDate);
10100 this.viewDate = new Date(this.date);
10107 var d = new Date(this.viewDate),
10108 year = d.getUTCFullYear(),
10109 month = d.getUTCMonth(),
10110 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
10111 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
10112 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
10113 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
10114 currentDate = this.date && this.date.valueOf(),
10115 today = this.UTCToday();
10117 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
10119 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
10121 // this.picker.select('>tfoot th.today').
10122 // .text(dates[this.language].today)
10123 // .toggle(this.todayBtn !== false);
10125 this.updateNavArrows();
10128 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
10130 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
10132 prevMonth.setUTCDate(day);
10134 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
10136 var nextMonth = new Date(prevMonth);
10138 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
10140 nextMonth = nextMonth.valueOf();
10142 var fillMonths = false;
10144 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
10146 while(prevMonth.valueOf() < nextMonth) {
10149 if (prevMonth.getUTCDay() === this.weekStart) {
10151 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
10159 if(this.calendarWeeks){
10160 // ISO 8601: First week contains first thursday.
10161 // ISO also states week starts on Monday, but we can be more abstract here.
10163 // Start of current week: based on weekstart/current date
10164 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
10165 // Thursday of this week
10166 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
10167 // First Thursday of year, year from thursday
10168 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
10169 // Calendar week: ms between thursdays, div ms per day, div 7 days
10170 calWeek = (th - yth) / 864e5 / 7 + 1;
10172 fillMonths.cn.push({
10180 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
10182 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
10185 if (this.todayHighlight &&
10186 prevMonth.getUTCFullYear() == today.getFullYear() &&
10187 prevMonth.getUTCMonth() == today.getMonth() &&
10188 prevMonth.getUTCDate() == today.getDate()) {
10189 clsName += ' today';
10192 if (currentDate && prevMonth.valueOf() === currentDate) {
10193 clsName += ' active';
10196 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
10197 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
10198 clsName += ' disabled';
10201 fillMonths.cn.push({
10203 cls: 'day ' + clsName,
10204 html: prevMonth.getDate()
10207 prevMonth.setDate(prevMonth.getDate()+1);
10210 var currentYear = this.date && this.date.getUTCFullYear();
10211 var currentMonth = this.date && this.date.getUTCMonth();
10213 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
10215 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
10216 v.removeClass('active');
10218 if(currentYear === year && k === currentMonth){
10219 v.addClass('active');
10222 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
10223 v.addClass('disabled');
10229 year = parseInt(year/10, 10) * 10;
10231 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
10233 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
10236 for (var i = -1; i < 11; i++) {
10237 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
10239 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
10247 showMode: function(dir) {
10249 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
10251 Roo.each(this.picker().select('>div',true).elements, function(v){
10252 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10255 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
10260 if(this.isInline) return;
10262 this.picker().removeClass(['bottom', 'top']);
10264 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
10266 * place to the top of element!
10270 this.picker().addClass('top');
10271 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10276 this.picker().addClass('bottom');
10278 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10281 parseDate : function(value){
10282 if(!value || value instanceof Date){
10285 var v = Date.parseDate(value, this.format);
10286 if (!v && this.useIso) {
10287 v = Date.parseDate(value, 'Y-m-d');
10289 if(!v && this.altFormats){
10290 if(!this.altFormatsArray){
10291 this.altFormatsArray = this.altFormats.split("|");
10293 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
10294 v = Date.parseDate(value, this.altFormatsArray[i]);
10300 formatDate : function(date, fmt){
10301 return (!date || !(date instanceof Date)) ?
10302 date : date.dateFormat(fmt || this.format);
10305 onFocus : function()
10307 Roo.bootstrap.DateField.superclass.onFocus.call(this);
10311 onBlur : function()
10313 Roo.bootstrap.DateField.superclass.onBlur.call(this);
10319 this.picker().show();
10326 if(this.isInline) return;
10327 this.picker().hide();
10328 this.viewMode = this.startViewMode;
10333 onMousedown: function(e){
10334 e.stopPropagation();
10335 e.preventDefault();
10338 keyup: function(e){
10339 Roo.bootstrap.DateField.superclass.keyup.call(this);
10344 fireKey: function(e){
10345 if (!this.picker().isVisible()){
10346 if (e.keyCode == 27) // allow escape to hide and re-show picker
10350 var dateChanged = false,
10352 newDate, newViewDate;
10356 e.preventDefault();
10360 if (!this.keyboardNavigation) break;
10361 dir = e.keyCode == 37 ? -1 : 1;
10364 newDate = this.moveYear(this.date, dir);
10365 newViewDate = this.moveYear(this.viewDate, dir);
10366 } else if (e.shiftKey){
10367 newDate = this.moveMonth(this.date, dir);
10368 newViewDate = this.moveMonth(this.viewDate, dir);
10370 newDate = new Date(this.date);
10371 newDate.setUTCDate(this.date.getUTCDate() + dir);
10372 newViewDate = new Date(this.viewDate);
10373 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
10375 if (this.dateWithinRange(newDate)){
10376 this.date = newDate;
10377 this.viewDate = newViewDate;
10378 this.setValue(this.formatDate(this.date));
10380 e.preventDefault();
10381 dateChanged = true;
10386 if (!this.keyboardNavigation) break;
10387 dir = e.keyCode == 38 ? -1 : 1;
10389 newDate = this.moveYear(this.date, dir);
10390 newViewDate = this.moveYear(this.viewDate, dir);
10391 } else if (e.shiftKey){
10392 newDate = this.moveMonth(this.date, dir);
10393 newViewDate = this.moveMonth(this.viewDate, dir);
10395 newDate = new Date(this.date);
10396 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
10397 newViewDate = new Date(this.viewDate);
10398 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
10400 if (this.dateWithinRange(newDate)){
10401 this.date = newDate;
10402 this.viewDate = newViewDate;
10403 this.setValue(this.formatDate(this.date));
10405 e.preventDefault();
10406 dateChanged = true;
10410 this.setValue(this.formatDate(this.date));
10412 e.preventDefault();
10415 this.setValue(this.formatDate(this.date));
10422 onClick: function(e) {
10423 e.stopPropagation();
10424 e.preventDefault();
10426 var target = e.getTarget();
10428 if(target.nodeName.toLowerCase() === 'i'){
10429 target = Roo.get(target).dom.parentNode;
10432 var nodeName = target.nodeName;
10433 var className = target.className;
10434 var html = target.innerHTML;
10436 switch(nodeName.toLowerCase()) {
10438 switch(className) {
10444 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
10445 switch(this.viewMode){
10447 this.viewDate = this.moveMonth(this.viewDate, dir);
10451 this.viewDate = this.moveYear(this.viewDate, dir);
10457 var date = new Date();
10458 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
10460 this.setValue(this.formatDate(this.date));
10466 if (className.indexOf('disabled') === -1) {
10467 this.viewDate.setUTCDate(1);
10468 if (className.indexOf('month') !== -1) {
10469 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
10471 var year = parseInt(html, 10) || 0;
10472 this.viewDate.setUTCFullYear(year);
10481 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
10482 var day = parseInt(html, 10) || 1;
10483 var year = this.viewDate.getUTCFullYear(),
10484 month = this.viewDate.getUTCMonth();
10486 if (className.indexOf('old') !== -1) {
10493 } else if (className.indexOf('new') !== -1) {
10501 this.date = this.UTCDate(year, month, day,0,0,0,0);
10502 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
10504 this.setValue(this.formatDate(this.date));
10511 setStartDate: function(startDate){
10512 this.startDate = startDate || -Infinity;
10513 if (this.startDate !== -Infinity) {
10514 this.startDate = this.parseDate(this.startDate);
10517 this.updateNavArrows();
10520 setEndDate: function(endDate){
10521 this.endDate = endDate || Infinity;
10522 if (this.endDate !== Infinity) {
10523 this.endDate = this.parseDate(this.endDate);
10526 this.updateNavArrows();
10529 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
10530 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
10531 if (typeof(this.daysOfWeekDisabled) !== 'object') {
10532 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
10534 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
10535 return parseInt(d, 10);
10538 this.updateNavArrows();
10541 updateNavArrows: function() {
10542 var d = new Date(this.viewDate),
10543 year = d.getUTCFullYear(),
10544 month = d.getUTCMonth();
10546 Roo.each(this.picker().select('.prev', true).elements, function(v){
10548 switch (this.viewMode) {
10551 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
10557 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
10564 Roo.each(this.picker().select('.next', true).elements, function(v){
10566 switch (this.viewMode) {
10569 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
10575 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
10583 moveMonth: function(date, dir){
10584 if (!dir) return date;
10585 var new_date = new Date(date.valueOf()),
10586 day = new_date.getUTCDate(),
10587 month = new_date.getUTCMonth(),
10588 mag = Math.abs(dir),
10590 dir = dir > 0 ? 1 : -1;
10593 // If going back one month, make sure month is not current month
10594 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
10596 return new_date.getUTCMonth() == month;
10598 // If going forward one month, make sure month is as expected
10599 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
10601 return new_date.getUTCMonth() != new_month;
10603 new_month = month + dir;
10604 new_date.setUTCMonth(new_month);
10605 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
10606 if (new_month < 0 || new_month > 11)
10607 new_month = (new_month + 12) % 12;
10609 // For magnitudes >1, move one month at a time...
10610 for (var i=0; i<mag; i++)
10611 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
10612 new_date = this.moveMonth(new_date, dir);
10613 // ...then reset the day, keeping it in the new month
10614 new_month = new_date.getUTCMonth();
10615 new_date.setUTCDate(day);
10617 return new_month != new_date.getUTCMonth();
10620 // Common date-resetting loop -- if date is beyond end of month, make it
10623 new_date.setUTCDate(--day);
10624 new_date.setUTCMonth(new_month);
10629 moveYear: function(date, dir){
10630 return this.moveMonth(date, dir*12);
10633 dateWithinRange: function(date){
10634 return date >= this.startDate && date <= this.endDate;
10638 remove: function() {
10639 this.picker().remove();
10644 Roo.apply(Roo.bootstrap.DateField, {
10655 html: '<i class="icon-arrow-left"/>'
10665 html: '<i class="icon-arrow-right"/>'
10707 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
10708 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
10709 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
10710 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
10711 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
10724 navFnc: 'FullYear',
10729 navFnc: 'FullYear',
10734 Roo.apply(Roo.bootstrap.DateField, {
10738 cls: 'datepicker dropdown-menu',
10742 cls: 'datepicker-days',
10746 cls: 'table-condensed',
10748 Roo.bootstrap.DateField.head,
10752 Roo.bootstrap.DateField.footer
10759 cls: 'datepicker-months',
10763 cls: 'table-condensed',
10765 Roo.bootstrap.DateField.head,
10766 Roo.bootstrap.DateField.content,
10767 Roo.bootstrap.DateField.footer
10774 cls: 'datepicker-years',
10778 cls: 'table-condensed',
10780 Roo.bootstrap.DateField.head,
10781 Roo.bootstrap.DateField.content,
10782 Roo.bootstrap.DateField.footer
10801 * @class Roo.bootstrap.CheckBox
10802 * @extends Roo.bootstrap.Input
10803 * Bootstrap CheckBox class
10805 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
10806 * @cfg {String} boxLabel The text that appears beside the checkbox
10807 * @cfg {Boolean} checked initnal the element
10810 * Create a new CheckBox
10811 * @param {Object} config The config object
10814 Roo.bootstrap.CheckBox = function(config){
10815 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
10820 * Fires when the element is checked or unchecked.
10821 * @param {Roo.bootstrap.CheckBox} this This input
10822 * @param {Boolean} checked The new checked value
10828 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
10830 inputType: 'checkbox',
10836 getAutoCreate : function()
10838 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10844 cfg.cls = 'form-group' //input-group
10849 type : this.inputType,
10850 value : (!this.checked) ? this.valueOff : this.value,
10852 placeholder : this.placeholder || ''
10856 if (this.disabled) {
10857 input.disabled=true;
10861 input.checked = this.checked;
10865 input.name = this.name;
10869 input.cls += ' input-' + this.size;
10873 ['xs','sm','md','lg'].map(function(size){
10874 if (settings[size]) {
10875 cfg.cls += ' col-' + size + '-' + settings[size];
10879 var inputblock = input;
10881 if (this.before || this.after) {
10884 cls : 'input-group',
10888 inputblock.cn.push({
10890 cls : 'input-group-addon',
10894 inputblock.cn.push(input);
10896 inputblock.cn.push({
10898 cls : 'input-group-addon',
10905 if (align ==='left' && this.fieldLabel.length) {
10906 Roo.log("left and has label");
10912 cls : 'control-label col-md-' + this.labelWidth,
10913 html : this.fieldLabel
10917 cls : "col-md-" + (12 - this.labelWidth),
10924 } else if ( this.fieldLabel.length) {
10931 cls: 'control-label box-input-label',
10932 //cls : 'input-group-addon',
10933 html : this.fieldLabel
10943 Roo.log(" no label && no align");
10958 html: this.boxLabel
10967 * return the real input element.
10969 inputEl: function ()
10971 return this.el.select('input.form-box',true).first();
10974 initEvents : function()
10976 Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
10978 this.inputEl().on('click', this.onClick, this);
10982 onClick : function()
10984 this.setChecked(!this.checked);
10987 setChecked : function(state,suppressEvent)
10989 this.checked = state;
10991 if(suppressEvent !== true){
10992 this.fireEvent('check', this, state);
10995 this.inputEl().dom.value = state ? this.value : this.valueOff;
11009 * @class Roo.bootstrap.Radio
11010 * @extends Roo.bootstrap.CheckBox
11011 * Bootstrap Radio class
11014 * Create a new Radio
11015 * @param {Object} config The config object
11018 Roo.bootstrap.Radio = function(config){
11019 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
11023 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
11025 inputType: 'radio',
11027 getAutoCreate : function()
11029 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11035 cfg.cls = 'form-group' //input-group
11040 type : this.inputType,
11041 value : (!this.checked) ? this.valueOff : this.value,
11043 placeholder : this.placeholder || ''
11047 if (this.disabled) {
11048 input.disabled=true;
11052 input.checked = this.checked;
11056 input.name = this.name;
11060 input.cls += ' input-' + this.size;
11064 ['xs','sm','md','lg'].map(function(size){
11065 if (settings[size]) {
11066 cfg.cls += ' col-' + size + '-' + settings[size];
11070 var inputblock = input;
11072 if (this.before || this.after) {
11075 cls : 'input-group',
11079 inputblock.cn.push({
11081 cls : 'input-group-addon',
11085 inputblock.cn.push(input);
11087 inputblock.cn.push({
11089 cls : 'input-group-addon',
11096 if (align ==='left' && this.fieldLabel.length) {
11097 Roo.log("left and has label");
11103 cls : 'control-label col-md-' + this.labelWidth,
11104 html : this.fieldLabel
11108 cls : "col-md-" + (12 - this.labelWidth),
11115 } else if ( this.fieldLabel.length) {
11122 cls: 'control-label box-input-label',
11123 //cls : 'input-group-addon',
11124 html : this.fieldLabel
11134 Roo.log(" no label && no align");
11149 html: this.boxLabel
11157 onClick : function()
11159 this.setChecked(true);
11162 setChecked : function(state,suppressEvent)
11164 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
11168 this.checked = state;
11170 if(suppressEvent !== true){
11171 this.fireEvent('check', this, state);
11174 this.inputEl().dom.value = state ? this.value : this.valueOff;
11178 getGroupValue : function()
11180 if(typeof(this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true)) == 'undefined'){
11184 return this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true).value;
11188 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
11189 * @return {Mixed} value The field value
11191 getValue : function(){
11192 return this.getGroupValue();
11206 * @class Roo.bootstrap.HtmlEditor
11207 * @extends Roo.bootstrap.Component
11208 * Bootstrap HtmlEditor class
11211 * Create a new HtmlEditor
11212 * @param {Object} config The config object
11215 Roo.bootstrap.HtmlEditor = function(config){
11216 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
11221 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.Component, {
11223 getAutoCreate : function()
11227 // var toolbar = new Roo.bootstrap.ButtonGroup({
11231 // new Roo.bootstrap.Button({
11244 * @class Roo.bootstrap.Table.AbstractSelectionModel
11245 * @extends Roo.util.Observable
11246 * Abstract base class for grid SelectionModels. It provides the interface that should be
11247 * implemented by descendant classes. This class should not be directly instantiated.
11250 Roo.bootstrap.Table.AbstractSelectionModel = function(){
11251 this.locked = false;
11252 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
11256 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
11257 /** @ignore Called by the grid automatically. Do not call directly. */
11258 init : function(grid){
11264 * Locks the selections.
11267 this.locked = true;
11271 * Unlocks the selections.
11273 unlock : function(){
11274 this.locked = false;
11278 * Returns true if the selections are locked.
11279 * @return {Boolean}
11281 isLocked : function(){
11282 return this.locked;
11286 * @class Roo.bootstrap.Table.ColumnModel
11287 * @extends Roo.util.Observable
11288 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
11289 * the columns in the table.
11292 * @param {Object} config An Array of column config objects. See this class's
11293 * config objects for details.
11295 Roo.bootstrap.Table.ColumnModel = function(config){
11297 * The config passed into the constructor
11299 this.config = config;
11302 // if no id, create one
11303 // if the column does not have a dataIndex mapping,
11304 // map it to the order it is in the config
11305 for(var i = 0, len = config.length; i < len; i++){
11307 if(typeof c.dataIndex == "undefined"){
11310 if(typeof c.renderer == "string"){
11311 c.renderer = Roo.util.Format[c.renderer];
11313 if(typeof c.id == "undefined"){
11316 // if(c.editor && c.editor.xtype){
11317 // c.editor = Roo.factory(c.editor, Roo.grid);
11319 // if(c.editor && c.editor.isFormField){
11320 // c.editor = new Roo.grid.GridEditor(c.editor);
11323 this.lookup[c.id] = c;
11327 * The width of columns which have no width specified (defaults to 100)
11330 this.defaultWidth = 100;
11333 * Default sortable of columns which have no sortable specified (defaults to false)
11336 this.defaultSortable = false;
11340 * @event widthchange
11341 * Fires when the width of a column changes.
11342 * @param {ColumnModel} this
11343 * @param {Number} columnIndex The column index
11344 * @param {Number} newWidth The new width
11346 "widthchange": true,
11348 * @event headerchange
11349 * Fires when the text of a header changes.
11350 * @param {ColumnModel} this
11351 * @param {Number} columnIndex The column index
11352 * @param {Number} newText The new header text
11354 "headerchange": true,
11356 * @event hiddenchange
11357 * Fires when a column is hidden or "unhidden".
11358 * @param {ColumnModel} this
11359 * @param {Number} columnIndex The column index
11360 * @param {Boolean} hidden true if hidden, false otherwise
11362 "hiddenchange": true,
11364 * @event columnmoved
11365 * Fires when a column is moved.
11366 * @param {ColumnModel} this
11367 * @param {Number} oldIndex
11368 * @param {Number} newIndex
11370 "columnmoved" : true,
11372 * @event columlockchange
11373 * Fires when a column's locked state is changed
11374 * @param {ColumnModel} this
11375 * @param {Number} colIndex
11376 * @param {Boolean} locked true if locked
11378 "columnlockchange" : true
11380 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
11382 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
11384 * @cfg {String} header The header text to display in the Grid view.
11387 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
11388 * {@link Roo.data.Record} definition from which to draw the column's value. If not
11389 * specified, the column's index is used as an index into the Record's data Array.
11392 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
11393 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
11396 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
11397 * Defaults to the value of the {@link #defaultSortable} property.
11398 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
11401 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
11404 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
11407 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
11410 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
11413 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
11414 * given the cell's data value. See {@link #setRenderer}. If not specified, the
11415 * default renderer uses the raw data value.
11418 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
11422 * Returns the id of the column at the specified index.
11423 * @param {Number} index The column index
11424 * @return {String} the id
11426 getColumnId : function(index){
11427 return this.config[index].id;
11431 * Returns the column for a specified id.
11432 * @param {String} id The column id
11433 * @return {Object} the column
11435 getColumnById : function(id){
11436 return this.lookup[id];
11441 * Returns the column for a specified dataIndex.
11442 * @param {String} dataIndex The column dataIndex
11443 * @return {Object|Boolean} the column or false if not found
11445 getColumnByDataIndex: function(dataIndex){
11446 var index = this.findColumnIndex(dataIndex);
11447 return index > -1 ? this.config[index] : false;
11451 * Returns the index for a specified column id.
11452 * @param {String} id The column id
11453 * @return {Number} the index, or -1 if not found
11455 getIndexById : function(id){
11456 for(var i = 0, len = this.config.length; i < len; i++){
11457 if(this.config[i].id == id){
11465 * Returns the index for a specified column dataIndex.
11466 * @param {String} dataIndex The column dataIndex
11467 * @return {Number} the index, or -1 if not found
11470 findColumnIndex : function(dataIndex){
11471 for(var i = 0, len = this.config.length; i < len; i++){
11472 if(this.config[i].dataIndex == dataIndex){
11480 moveColumn : function(oldIndex, newIndex){
11481 var c = this.config[oldIndex];
11482 this.config.splice(oldIndex, 1);
11483 this.config.splice(newIndex, 0, c);
11484 this.dataMap = null;
11485 this.fireEvent("columnmoved", this, oldIndex, newIndex);
11488 isLocked : function(colIndex){
11489 return this.config[colIndex].locked === true;
11492 setLocked : function(colIndex, value, suppressEvent){
11493 if(this.isLocked(colIndex) == value){
11496 this.config[colIndex].locked = value;
11497 if(!suppressEvent){
11498 this.fireEvent("columnlockchange", this, colIndex, value);
11502 getTotalLockedWidth : function(){
11503 var totalWidth = 0;
11504 for(var i = 0; i < this.config.length; i++){
11505 if(this.isLocked(i) && !this.isHidden(i)){
11506 this.totalWidth += this.getColumnWidth(i);
11512 getLockedCount : function(){
11513 for(var i = 0, len = this.config.length; i < len; i++){
11514 if(!this.isLocked(i)){
11521 * Returns the number of columns.
11524 getColumnCount : function(visibleOnly){
11525 if(visibleOnly === true){
11527 for(var i = 0, len = this.config.length; i < len; i++){
11528 if(!this.isHidden(i)){
11534 return this.config.length;
11538 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
11539 * @param {Function} fn
11540 * @param {Object} scope (optional)
11541 * @return {Array} result
11543 getColumnsBy : function(fn, scope){
11545 for(var i = 0, len = this.config.length; i < len; i++){
11546 var c = this.config[i];
11547 if(fn.call(scope||this, c, i) === true){
11555 * Returns true if the specified column is sortable.
11556 * @param {Number} col The column index
11557 * @return {Boolean}
11559 isSortable : function(col){
11560 if(typeof this.config[col].sortable == "undefined"){
11561 return this.defaultSortable;
11563 return this.config[col].sortable;
11567 * Returns the rendering (formatting) function defined for the column.
11568 * @param {Number} col The column index.
11569 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
11571 getRenderer : function(col){
11572 if(!this.config[col].renderer){
11573 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
11575 return this.config[col].renderer;
11579 * Sets the rendering (formatting) function for a column.
11580 * @param {Number} col The column index
11581 * @param {Function} fn The function to use to process the cell's raw data
11582 * to return HTML markup for the grid view. The render function is called with
11583 * the following parameters:<ul>
11584 * <li>Data value.</li>
11585 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
11586 * <li>css A CSS style string to apply to the table cell.</li>
11587 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
11588 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
11589 * <li>Row index</li>
11590 * <li>Column index</li>
11591 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
11593 setRenderer : function(col, fn){
11594 this.config[col].renderer = fn;
11598 * Returns the width for the specified column.
11599 * @param {Number} col The column index
11602 getColumnWidth : function(col){
11603 return this.config[col].width * 1 || this.defaultWidth;
11607 * Sets the width for a column.
11608 * @param {Number} col The column index
11609 * @param {Number} width The new width
11611 setColumnWidth : function(col, width, suppressEvent){
11612 this.config[col].width = width;
11613 this.totalWidth = null;
11614 if(!suppressEvent){
11615 this.fireEvent("widthchange", this, col, width);
11620 * Returns the total width of all columns.
11621 * @param {Boolean} includeHidden True to include hidden column widths
11624 getTotalWidth : function(includeHidden){
11625 if(!this.totalWidth){
11626 this.totalWidth = 0;
11627 for(var i = 0, len = this.config.length; i < len; i++){
11628 if(includeHidden || !this.isHidden(i)){
11629 this.totalWidth += this.getColumnWidth(i);
11633 return this.totalWidth;
11637 * Returns the header for the specified column.
11638 * @param {Number} col The column index
11641 getColumnHeader : function(col){
11642 return this.config[col].header;
11646 * Sets the header for a column.
11647 * @param {Number} col The column index
11648 * @param {String} header The new header
11650 setColumnHeader : function(col, header){
11651 this.config[col].header = header;
11652 this.fireEvent("headerchange", this, col, header);
11656 * Returns the tooltip for the specified column.
11657 * @param {Number} col The column index
11660 getColumnTooltip : function(col){
11661 return this.config[col].tooltip;
11664 * Sets the tooltip for a column.
11665 * @param {Number} col The column index
11666 * @param {String} tooltip The new tooltip
11668 setColumnTooltip : function(col, tooltip){
11669 this.config[col].tooltip = tooltip;
11673 * Returns the dataIndex for the specified column.
11674 * @param {Number} col The column index
11677 getDataIndex : function(col){
11678 return this.config[col].dataIndex;
11682 * Sets the dataIndex for a column.
11683 * @param {Number} col The column index
11684 * @param {Number} dataIndex The new dataIndex
11686 setDataIndex : function(col, dataIndex){
11687 this.config[col].dataIndex = dataIndex;
11693 * Returns true if the cell is editable.
11694 * @param {Number} colIndex The column index
11695 * @param {Number} rowIndex The row index
11696 * @return {Boolean}
11698 isCellEditable : function(colIndex, rowIndex){
11699 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
11703 * Returns the editor defined for the cell/column.
11704 * return false or null to disable editing.
11705 * @param {Number} colIndex The column index
11706 * @param {Number} rowIndex The row index
11709 getCellEditor : function(colIndex, rowIndex){
11710 return this.config[colIndex].editor;
11714 * Sets if a column is editable.
11715 * @param {Number} col The column index
11716 * @param {Boolean} editable True if the column is editable
11718 setEditable : function(col, editable){
11719 this.config[col].editable = editable;
11724 * Returns true if the column is hidden.
11725 * @param {Number} colIndex The column index
11726 * @return {Boolean}
11728 isHidden : function(colIndex){
11729 return this.config[colIndex].hidden;
11734 * Returns true if the column width cannot be changed
11736 isFixed : function(colIndex){
11737 return this.config[colIndex].fixed;
11741 * Returns true if the column can be resized
11742 * @return {Boolean}
11744 isResizable : function(colIndex){
11745 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
11748 * Sets if a column is hidden.
11749 * @param {Number} colIndex The column index
11750 * @param {Boolean} hidden True if the column is hidden
11752 setHidden : function(colIndex, hidden){
11753 this.config[colIndex].hidden = hidden;
11754 this.totalWidth = null;
11755 this.fireEvent("hiddenchange", this, colIndex, hidden);
11759 * Sets the editor for a column.
11760 * @param {Number} col The column index
11761 * @param {Object} editor The editor object
11763 setEditor : function(col, editor){
11764 this.config[col].editor = editor;
11768 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
11769 if(typeof value == "string" && value.length < 1){
11775 // Alias for backwards compatibility
11776 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
11779 * @extends Roo.bootstrap.Table.AbstractSelectionModel
11780 * @class Roo.bootstrap.Table.RowSelectionModel
11781 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
11782 * It supports multiple selections and keyboard selection/navigation.
11784 * @param {Object} config
11787 Roo.bootstrap.Table.RowSelectionModel = function(config){
11788 Roo.apply(this, config);
11789 this.selections = new Roo.util.MixedCollection(false, function(o){
11794 this.lastActive = false;
11798 * @event selectionchange
11799 * Fires when the selection changes
11800 * @param {SelectionModel} this
11802 "selectionchange" : true,
11804 * @event afterselectionchange
11805 * Fires after the selection changes (eg. by key press or clicking)
11806 * @param {SelectionModel} this
11808 "afterselectionchange" : true,
11810 * @event beforerowselect
11811 * Fires when a row is selected being selected, return false to cancel.
11812 * @param {SelectionModel} this
11813 * @param {Number} rowIndex The selected index
11814 * @param {Boolean} keepExisting False if other selections will be cleared
11816 "beforerowselect" : true,
11819 * Fires when a row is selected.
11820 * @param {SelectionModel} this
11821 * @param {Number} rowIndex The selected index
11822 * @param {Roo.data.Record} r The record
11824 "rowselect" : true,
11826 * @event rowdeselect
11827 * Fires when a row is deselected.
11828 * @param {SelectionModel} this
11829 * @param {Number} rowIndex The selected index
11831 "rowdeselect" : true
11833 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
11834 this.locked = false;
11837 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
11839 * @cfg {Boolean} singleSelect
11840 * True to allow selection of only one row at a time (defaults to false)
11842 singleSelect : false,
11845 initEvents : function(){
11847 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
11848 this.grid.on("mousedown", this.handleMouseDown, this);
11849 }else{ // allow click to work like normal
11850 this.grid.on("rowclick", this.handleDragableRowClick, this);
11853 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
11854 "up" : function(e){
11856 this.selectPrevious(e.shiftKey);
11857 }else if(this.last !== false && this.lastActive !== false){
11858 var last = this.last;
11859 this.selectRange(this.last, this.lastActive-1);
11860 this.grid.getView().focusRow(this.lastActive);
11861 if(last !== false){
11865 this.selectFirstRow();
11867 this.fireEvent("afterselectionchange", this);
11869 "down" : function(e){
11871 this.selectNext(e.shiftKey);
11872 }else if(this.last !== false && this.lastActive !== false){
11873 var last = this.last;
11874 this.selectRange(this.last, this.lastActive+1);
11875 this.grid.getView().focusRow(this.lastActive);
11876 if(last !== false){
11880 this.selectFirstRow();
11882 this.fireEvent("afterselectionchange", this);
11887 var view = this.grid.view;
11888 view.on("refresh", this.onRefresh, this);
11889 view.on("rowupdated", this.onRowUpdated, this);
11890 view.on("rowremoved", this.onRemove, this);
11894 onRefresh : function(){
11895 var ds = this.grid.dataSource, i, v = this.grid.view;
11896 var s = this.selections;
11897 s.each(function(r){
11898 if((i = ds.indexOfId(r.id)) != -1){
11907 onRemove : function(v, index, r){
11908 this.selections.remove(r);
11912 onRowUpdated : function(v, index, r){
11913 if(this.isSelected(r)){
11914 v.onRowSelect(index);
11920 * @param {Array} records The records to select
11921 * @param {Boolean} keepExisting (optional) True to keep existing selections
11923 selectRecords : function(records, keepExisting){
11925 this.clearSelections();
11927 var ds = this.grid.dataSource;
11928 for(var i = 0, len = records.length; i < len; i++){
11929 this.selectRow(ds.indexOf(records[i]), true);
11934 * Gets the number of selected rows.
11937 getCount : function(){
11938 return this.selections.length;
11942 * Selects the first row in the grid.
11944 selectFirstRow : function(){
11949 * Select the last row.
11950 * @param {Boolean} keepExisting (optional) True to keep existing selections
11952 selectLastRow : function(keepExisting){
11953 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
11957 * Selects the row immediately following the last selected row.
11958 * @param {Boolean} keepExisting (optional) True to keep existing selections
11960 selectNext : function(keepExisting){
11961 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
11962 this.selectRow(this.last+1, keepExisting);
11963 this.grid.getView().focusRow(this.last);
11968 * Selects the row that precedes the last selected row.
11969 * @param {Boolean} keepExisting (optional) True to keep existing selections
11971 selectPrevious : function(keepExisting){
11973 this.selectRow(this.last-1, keepExisting);
11974 this.grid.getView().focusRow(this.last);
11979 * Returns the selected records
11980 * @return {Array} Array of selected records
11982 getSelections : function(){
11983 return [].concat(this.selections.items);
11987 * Returns the first selected record.
11990 getSelected : function(){
11991 return this.selections.itemAt(0);
11996 * Clears all selections.
11998 clearSelections : function(fast){
11999 if(this.locked) return;
12001 var ds = this.grid.dataSource;
12002 var s = this.selections;
12003 s.each(function(r){
12004 this.deselectRow(ds.indexOfId(r.id));
12008 this.selections.clear();
12015 * Selects all rows.
12017 selectAll : function(){
12018 if(this.locked) return;
12019 this.selections.clear();
12020 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
12021 this.selectRow(i, true);
12026 * Returns True if there is a selection.
12027 * @return {Boolean}
12029 hasSelection : function(){
12030 return this.selections.length > 0;
12034 * Returns True if the specified row is selected.
12035 * @param {Number/Record} record The record or index of the record to check
12036 * @return {Boolean}
12038 isSelected : function(index){
12039 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
12040 return (r && this.selections.key(r.id) ? true : false);
12044 * Returns True if the specified record id is selected.
12045 * @param {String} id The id of record to check
12046 * @return {Boolean}
12048 isIdSelected : function(id){
12049 return (this.selections.key(id) ? true : false);
12053 handleMouseDown : function(e, t){
12054 var view = this.grid.getView(), rowIndex;
12055 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
12058 if(e.shiftKey && this.last !== false){
12059 var last = this.last;
12060 this.selectRange(last, rowIndex, e.ctrlKey);
12061 this.last = last; // reset the last
12062 view.focusRow(rowIndex);
12064 var isSelected = this.isSelected(rowIndex);
12065 if(e.button !== 0 && isSelected){
12066 view.focusRow(rowIndex);
12067 }else if(e.ctrlKey && isSelected){
12068 this.deselectRow(rowIndex);
12069 }else if(!isSelected){
12070 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
12071 view.focusRow(rowIndex);
12074 this.fireEvent("afterselectionchange", this);
12077 handleDragableRowClick : function(grid, rowIndex, e)
12079 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
12080 this.selectRow(rowIndex, false);
12081 grid.view.focusRow(rowIndex);
12082 this.fireEvent("afterselectionchange", this);
12087 * Selects multiple rows.
12088 * @param {Array} rows Array of the indexes of the row to select
12089 * @param {Boolean} keepExisting (optional) True to keep existing selections
12091 selectRows : function(rows, keepExisting){
12093 this.clearSelections();
12095 for(var i = 0, len = rows.length; i < len; i++){
12096 this.selectRow(rows[i], true);
12101 * Selects a range of rows. All rows in between startRow and endRow are also selected.
12102 * @param {Number} startRow The index of the first row in the range
12103 * @param {Number} endRow The index of the last row in the range
12104 * @param {Boolean} keepExisting (optional) True to retain existing selections
12106 selectRange : function(startRow, endRow, keepExisting){
12107 if(this.locked) return;
12109 this.clearSelections();
12111 if(startRow <= endRow){
12112 for(var i = startRow; i <= endRow; i++){
12113 this.selectRow(i, true);
12116 for(var i = startRow; i >= endRow; i--){
12117 this.selectRow(i, true);
12123 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
12124 * @param {Number} startRow The index of the first row in the range
12125 * @param {Number} endRow The index of the last row in the range
12127 deselectRange : function(startRow, endRow, preventViewNotify){
12128 if(this.locked) return;
12129 for(var i = startRow; i <= endRow; i++){
12130 this.deselectRow(i, preventViewNotify);
12136 * @param {Number} row The index of the row to select
12137 * @param {Boolean} keepExisting (optional) True to keep existing selections
12139 selectRow : function(index, keepExisting, preventViewNotify){
12140 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
12141 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
12142 if(!keepExisting || this.singleSelect){
12143 this.clearSelections();
12145 var r = this.grid.dataSource.getAt(index);
12146 this.selections.add(r);
12147 this.last = this.lastActive = index;
12148 if(!preventViewNotify){
12149 this.grid.getView().onRowSelect(index);
12151 this.fireEvent("rowselect", this, index, r);
12152 this.fireEvent("selectionchange", this);
12158 * @param {Number} row The index of the row to deselect
12160 deselectRow : function(index, preventViewNotify){
12161 if(this.locked) return;
12162 if(this.last == index){
12165 if(this.lastActive == index){
12166 this.lastActive = false;
12168 var r = this.grid.dataSource.getAt(index);
12169 this.selections.remove(r);
12170 if(!preventViewNotify){
12171 this.grid.getView().onRowDeselect(index);
12173 this.fireEvent("rowdeselect", this, index);
12174 this.fireEvent("selectionchange", this);
12178 restoreLast : function(){
12180 this.last = this._last;
12185 acceptsNav : function(row, col, cm){
12186 return !cm.isHidden(col) && cm.isCellEditable(col, row);
12190 onEditorKey : function(field, e){
12191 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
12196 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
12198 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
12200 }else if(k == e.ENTER && !e.ctrlKey){
12204 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
12206 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
12208 }else if(k == e.ESC){
12212 g.startEditing(newCell[0], newCell[1]);