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') {
194 var test = Roo.factory(tree);
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
1530 * Create a new Navbar
1531 * @param {Object} config The config object
1535 Roo.bootstrap.Navbar = function(config){
1536 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
1539 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
1552 getAutoCreate : function(){
1557 if (this.sidebar === true) {
1565 if (this.bar === true) {
1573 cls: 'navbar-header',
1578 cls: 'navbar-toggle',
1579 'data-toggle': 'collapse',
1584 html: 'Toggle navigation'
1604 cls: 'collapse navbar-collapse'
1609 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
1611 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
1612 cfg.cls += ' navbar-' + this.position;
1613 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
1616 if (this.brand !== '') {
1619 href: this.brand_href ? this.brand_href : '#',
1620 cls: 'navbar-brand',
1629 } else if (this.bar === false) {
1632 Roo.log('Property \'bar\' in of Navbar must be either true or false')
1642 if (['tabs','pills'].indexOf(this.type)!==-1) {
1643 cfg.cn[0].cls += ' nav-' + this.type
1645 if (this.type!=='nav') {
1646 Roo.log('nav type must be nav/tabs/pills')
1648 cfg.cn[0].cls += ' navbar-nav'
1651 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
1652 cfg.cn[0].cls += ' nav-' + this.arrangement;
1655 if (this.align === 'right') {
1656 cfg.cn[0].cls += ' navbar-right';
1659 cfg.cls += ' navbar-inverse';
1667 initEvents :function ()
1669 //Roo.log(this.el.select('.navbar-toggle',true));
1670 this.el.select('.navbar-toggle',true).on('click', function() {
1671 // Roo.log('click');
1672 this.el.select('.navbar-collapse',true).toggleClass('in');
1677 getChildContainer : function()
1679 if (this.bar === true) {
1680 return this.el.select('.collapse',true).first();
1698 * @class Roo.bootstrap.NavGroup
1699 * @extends Roo.bootstrap.Component
1700 * Bootstrap NavGroup class
1701 * @cfg {String} align left | right
1702 * @cfg {Boolean} inverse false | true
1703 * @cfg {String} type (nav|pills|tab) default nav
1706 * Create a new nav group
1707 * @param {Object} config The config object
1710 Roo.bootstrap.NavGroup = function(config){
1711 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
1714 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
1721 getAutoCreate : function(){
1722 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
1729 if (['tabs','pills'].indexOf(this.type)!==-1) {
1730 cfg.cls += ' nav-' + this.type
1732 if (this.type!=='nav') {
1733 Roo.log('nav type must be nav/tabs/pills')
1735 cfg.cls += ' navbar-nav'
1738 if (this.parent().sidebar === true) {
1741 cls: 'dashboard-menu'
1747 if (this.form === true) {
1753 if (this.align === 'right') {
1754 cfg.cls += ' navbar-right';
1756 cfg.cls += ' navbar-left';
1760 if (this.align === 'right') {
1761 cfg.cls += ' navbar-right';
1765 cfg.cls += ' navbar-inverse';
1785 * @class Roo.bootstrap.Navbar.Item
1786 * @extends Roo.bootstrap.Component
1787 * Bootstrap Navbar.Button class
1788 * @cfg {String} href link to
1789 * @cfg {String} html content of button
1790 * @cfg {String} badge text inside badge
1791 * @cfg {String} glyphicon name of glyphicon
1792 * @cfg {String} icon name of font awesome icon
1793 * @cfg {Boolena} active Is item active
1794 * @cfg {Boolean} preventDefault (true | false) default false
1797 * Create a new Navbar Button
1798 * @param {Object} config The config object
1800 Roo.bootstrap.Navbar.Item = function(config){
1801 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1806 * The raw click event for the entire grid.
1807 * @param {Roo.EventObject} e
1813 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
1822 preventDefault : false,
1824 getAutoCreate : function(){
1826 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1828 if (this.parent().parent().sidebar === true) {
1841 cfg.cn[0].html = this.html;
1845 this.cls += ' active';
1849 cfg.cn[0].cls += ' dropdown-toggle';
1850 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1854 cfg.cn[0].tag = 'a',
1855 cfg.cn[0].href = this.href;
1858 if (this.glyphicon) {
1859 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1863 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1874 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
1884 if (this.glyphicon) {
1885 if(cfg.html){cfg.html = ' ' + this.html};
1889 cls: 'glyphicon glyphicon-' + this.glyphicon
1894 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1899 cfg.cn[0].html += " <span class='caret'></span>";
1900 //}else if (!this.href) {
1901 // cfg.cn[0].tag='p';
1902 // cfg.cn[0].cls='navbar-text';
1905 cfg.cn[0].href=this.href||'#';
1906 cfg.cn[0].html=this.html;
1909 if (this.badge !== '') {
1912 cfg.cn[0].html + ' ',
1923 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1928 initEvents: function() {
1929 // Roo.log('init events?');
1930 // Roo.log(this.el.dom);
1931 this.el.select('a',true).on('click', this.onClick, this);
1934 onClick : function(e)
1936 if(this.preventDefault){
1940 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
1941 this.onTabsClick(e);
1944 this.fireEvent('click', this, e);
1947 onTabsClick : function(e)
1949 Roo.each(this.parent().el.select('.active',true).elements, function(v){
1950 v.removeClass('active');
1953 this.el.addClass('active');
1955 if(this.href && this.href.substring(0,1) == '#'){
1956 var tab = Roo.select('[tabId=' + this.href + ']', true).first();
1958 Roo.each(tab.findParent('.tab-content', 0, true).select('.active', true).elements, function(v){
1959 v.removeClass('active');
1962 tab.addClass('active');
1977 * @class Roo.bootstrap.Row
1978 * @extends Roo.bootstrap.Component
1979 * Bootstrap Row class (contains columns...)
1983 * @param {Object} config The config object
1986 Roo.bootstrap.Row = function(config){
1987 Roo.bootstrap.Row.superclass.constructor.call(this, config);
1990 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
1992 getAutoCreate : function(){
2011 * @class Roo.bootstrap.Element
2012 * @extends Roo.bootstrap.Component
2013 * Bootstrap Element class
2014 * @cfg {String} html contents of the element
2015 * @cfg {String} tag tag of the element
2016 * @cfg {String} cls class of the element
2019 * Create a new Element
2020 * @param {Object} config The config object
2023 Roo.bootstrap.Element = function(config){
2024 Roo.bootstrap.Element.superclass.constructor.call(this, config);
2027 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
2034 getAutoCreate : function(){
2057 * @class Roo.bootstrap.Pagination
2058 * @extends Roo.bootstrap.Component
2059 * Bootstrap Pagination class
2060 * @cfg {String} size xs | sm | md | lg
2061 * @cfg {Boolean} inverse false | true
2064 * Create a new Pagination
2065 * @param {Object} config The config object
2068 Roo.bootstrap.Pagination = function(config){
2069 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
2072 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
2078 getAutoCreate : function(){
2084 cfg.cls += ' inverse';
2090 cfg.cls += " " + this.cls;
2108 * @class Roo.bootstrap.PaginationItem
2109 * @extends Roo.bootstrap.Component
2110 * Bootstrap PaginationItem class
2111 * @cfg {String} html text
2112 * @cfg {String} href the link
2113 * @cfg {Boolean} preventDefault (true | false) default true
2114 * @cfg {Boolean} active (true | false) default false
2118 * Create a new PaginationItem
2119 * @param {Object} config The config object
2123 Roo.bootstrap.PaginationItem = function(config){
2124 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
2129 * The raw click event for the entire grid.
2130 * @param {Roo.EventObject} e
2136 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
2140 preventDefault: true,
2144 getAutoCreate : function(){
2150 href : this.href ? this.href : '#',
2151 html : this.html ? this.html : ''
2161 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
2167 initEvents: function() {
2169 this.el.on('click', this.onClick, this);
2172 onClick : function(e)
2174 Roo.log('PaginationItem on click ');
2175 if(this.preventDefault){
2179 this.fireEvent('click', this, e);
2195 * @class Roo.bootstrap.Slider
2196 * @extends Roo.bootstrap.Component
2197 * Bootstrap Slider class
2200 * Create a new Slider
2201 * @param {Object} config The config object
2204 Roo.bootstrap.Slider = function(config){
2205 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
2208 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
2210 getAutoCreate : function(){
2214 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
2218 cls: 'ui-slider-handle ui-state-default ui-corner-all'
2236 * @class Roo.bootstrap.Table
2237 * @extends Roo.bootstrap.Component
2238 * Bootstrap Table class
2239 * @cfg {String} cls table class
2240 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
2241 * @cfg {String} bgcolor Specifies the background color for a table
2242 * @cfg {Number} border Specifies whether the table cells should have borders or not
2243 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
2244 * @cfg {Number} cellspacing Specifies the space between cells
2245 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
2246 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
2247 * @cfg {String} sortable Specifies that the table should be sortable
2248 * @cfg {String} summary Specifies a summary of the content of a table
2249 * @cfg {Number} width Specifies the width of a table
2251 * @cfg {boolean} striped Should the rows be alternative striped
2252 * @cfg {boolean} bordered Add borders to the table
2253 * @cfg {boolean} hover Add hover highlighting
2254 * @cfg {boolean} condensed Format condensed
2255 * @cfg {boolean} responsive Format condensed
2261 * Create a new Table
2262 * @param {Object} config The config object
2265 Roo.bootstrap.Table = function(config){
2266 Roo.bootstrap.Table.superclass.constructor.call(this, config);
2269 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
2290 getAutoCreate : function(){
2291 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2299 cfg.cls += ' table-striped';
2302 cfg.cls += ' table-hover';
2304 if (this.bordered) {
2305 cfg.cls += ' table-bordered';
2307 if (this.condensed) {
2308 cfg.cls += ' table-condensed';
2310 if (this.responsive) {
2311 cfg.cls += ' table-responsive';
2318 cfg.cls+= ' ' +this.cls;
2321 // this lot should be simplifed...
2324 cfg.align=this.align;
2327 cfg.bgcolor=this.bgcolor;
2330 cfg.border=this.border;
2332 if (this.cellpadding) {
2333 cfg.cellpadding=this.cellpadding;
2335 if (this.cellspacing) {
2336 cfg.cellspacing=this.cellspacing;
2339 cfg.frame=this.frame;
2342 cfg.rules=this.rules;
2344 if (this.sortable) {
2345 cfg.sortable=this.sortable;
2348 cfg.summary=this.summary;
2351 cfg.width=this.width;
2371 * @class Roo.bootstrap.TableCell
2372 * @extends Roo.bootstrap.Component
2373 * Bootstrap TableCell class
2374 * @cfg {String} html cell contain text
2375 * @cfg {String} cls cell class
2376 * @cfg {String} tag cell tag (td|th) default td
2377 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
2378 * @cfg {String} align Aligns the content in a cell
2379 * @cfg {String} axis Categorizes cells
2380 * @cfg {String} bgcolor Specifies the background color of a cell
2381 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
2382 * @cfg {Number} colspan Specifies the number of columns a cell should span
2383 * @cfg {String} headers Specifies one or more header cells a cell is related to
2384 * @cfg {Number} height Sets the height of a cell
2385 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
2386 * @cfg {Number} rowspan Sets the number of rows a cell should span
2387 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
2388 * @cfg {String} valign Vertical aligns the content in a cell
2389 * @cfg {Number} width Specifies the width of a cell
2392 * Create a new TableCell
2393 * @param {Object} config The config object
2396 Roo.bootstrap.TableCell = function(config){
2397 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
2400 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
2420 getAutoCreate : function(){
2421 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
2441 cfg.align=this.align
2447 cfg.bgcolor=this.bgcolor
2450 cfg.charoff=this.charoff
2453 cfg.colspan=this.colspan
2456 cfg.headers=this.headers
2459 cfg.height=this.height
2462 cfg.nowrap=this.nowrap
2465 cfg.rowspan=this.rowspan
2468 cfg.scope=this.scope
2471 cfg.valign=this.valign
2474 cfg.width=this.width
2493 * @class Roo.bootstrap.TableRow
2494 * @extends Roo.bootstrap.Component
2495 * Bootstrap TableRow class
2496 * @cfg {String} cls row class
2497 * @cfg {String} align Aligns the content in a table row
2498 * @cfg {String} bgcolor Specifies a background color for a table row
2499 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
2500 * @cfg {String} valign Vertical aligns the content in a table row
2503 * Create a new TableRow
2504 * @param {Object} config The config object
2507 Roo.bootstrap.TableRow = function(config){
2508 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2511 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
2519 getAutoCreate : function(){
2520 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2530 cfg.align = this.align;
2533 cfg.bgcolor = this.bgcolor;
2536 cfg.charoff = this.charoff;
2539 cfg.valign = this.valign;
2557 * @class Roo.bootstrap.TableBody
2558 * @extends Roo.bootstrap.Component
2559 * Bootstrap TableBody class
2560 * @cfg {String} cls element class
2561 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
2562 * @cfg {String} align Aligns the content inside the element
2563 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
2564 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
2567 * Create a new TableBody
2568 * @param {Object} config The config object
2571 Roo.bootstrap.TableBody = function(config){
2572 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
2575 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
2583 getAutoCreate : function(){
2584 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
2598 cfg.align = this.align;
2601 cfg.charoff = this.charoff;
2604 cfg.valign = this.valign;
2616 * Ext JS Library 1.1.1
2617 * Copyright(c) 2006-2007, Ext JS, LLC.
2619 * Originally Released Under LGPL - original licence link has changed is not relivant.
2622 * <script type="text/javascript">
2625 // as we use this in bootstrap.
2626 Roo.namespace('Roo.form');
2628 * @class Roo.form.Action
2629 * Internal Class used to handle form actions
2631 * @param {Roo.form.BasicForm} el The form element or its id
2632 * @param {Object} config Configuration options
2637 // define the action interface
2638 Roo.form.Action = function(form, options){
2640 this.options = options || {};
2643 * Client Validation Failed
2646 Roo.form.Action.CLIENT_INVALID = 'client';
2648 * Server Validation Failed
2651 Roo.form.Action.SERVER_INVALID = 'server';
2653 * Connect to Server Failed
2656 Roo.form.Action.CONNECT_FAILURE = 'connect';
2658 * Reading Data from Server Failed
2661 Roo.form.Action.LOAD_FAILURE = 'load';
2663 Roo.form.Action.prototype = {
2665 failureType : undefined,
2666 response : undefined,
2670 run : function(options){
2675 success : function(response){
2680 handleResponse : function(response){
2684 // default connection failure
2685 failure : function(response){
2687 this.response = response;
2688 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2689 this.form.afterAction(this, false);
2692 processResponse : function(response){
2693 this.response = response;
2694 if(!response.responseText){
2697 this.result = this.handleResponse(response);
2701 // utility functions used internally
2702 getUrl : function(appendParams){
2703 var url = this.options.url || this.form.url || this.form.el.dom.action;
2705 var p = this.getParams();
2707 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2713 getMethod : function(){
2714 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2717 getParams : function(){
2718 var bp = this.form.baseParams;
2719 var p = this.options.params;
2721 if(typeof p == "object"){
2722 p = Roo.urlEncode(Roo.applyIf(p, bp));
2723 }else if(typeof p == 'string' && bp){
2724 p += '&' + Roo.urlEncode(bp);
2727 p = Roo.urlEncode(bp);
2732 createCallback : function(){
2734 success: this.success,
2735 failure: this.failure,
2737 timeout: (this.form.timeout*1000),
2738 upload: this.form.fileUpload ? this.success : undefined
2743 Roo.form.Action.Submit = function(form, options){
2744 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
2747 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
2750 haveProgress : false,
2751 uploadComplete : false,
2753 // uploadProgress indicator.
2754 uploadProgress : function()
2756 if (!this.form.progressUrl) {
2760 if (!this.haveProgress) {
2761 Roo.MessageBox.progress("Uploading", "Uploading");
2763 if (this.uploadComplete) {
2764 Roo.MessageBox.hide();
2768 this.haveProgress = true;
2770 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
2772 var c = new Roo.data.Connection();
2774 url : this.form.progressUrl,
2779 success : function(req){
2780 //console.log(data);
2784 rdata = Roo.decode(req.responseText)
2786 Roo.log("Invalid data from server..");
2790 if (!rdata || !rdata.success) {
2792 Roo.MessageBox.alert(Roo.encode(rdata));
2795 var data = rdata.data;
2797 if (this.uploadComplete) {
2798 Roo.MessageBox.hide();
2803 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
2804 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
2807 this.uploadProgress.defer(2000,this);
2810 failure: function(data) {
2811 Roo.log('progress url failed ');
2822 // run get Values on the form, so it syncs any secondary forms.
2823 this.form.getValues();
2825 var o = this.options;
2826 var method = this.getMethod();
2827 var isPost = method == 'POST';
2828 if(o.clientValidation === false || this.form.isValid()){
2830 if (this.form.progressUrl) {
2831 this.form.findField('UPLOAD_IDENTIFIER').setValue(
2832 (new Date() * 1) + '' + Math.random());
2837 Roo.Ajax.request(Roo.apply(this.createCallback(), {
2838 form:this.form.el.dom,
2839 url:this.getUrl(!isPost),
2841 params:isPost ? this.getParams() : null,
2842 isUpload: this.form.fileUpload
2845 this.uploadProgress();
2847 }else if (o.clientValidation !== false){ // client validation failed
2848 this.failureType = Roo.form.Action.CLIENT_INVALID;
2849 this.form.afterAction(this, false);
2853 success : function(response)
2855 this.uploadComplete= true;
2856 if (this.haveProgress) {
2857 Roo.MessageBox.hide();
2861 var result = this.processResponse(response);
2862 if(result === true || result.success){
2863 this.form.afterAction(this, true);
2867 this.form.markInvalid(result.errors);
2868 this.failureType = Roo.form.Action.SERVER_INVALID;
2870 this.form.afterAction(this, false);
2872 failure : function(response)
2874 this.uploadComplete= true;
2875 if (this.haveProgress) {
2876 Roo.MessageBox.hide();
2879 this.response = response;
2880 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2881 this.form.afterAction(this, false);
2884 handleResponse : function(response){
2885 if(this.form.errorReader){
2886 var rs = this.form.errorReader.read(response);
2889 for(var i = 0, len = rs.records.length; i < len; i++) {
2890 var r = rs.records[i];
2894 if(errors.length < 1){
2898 success : rs.success,
2904 ret = Roo.decode(response.responseText);
2908 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
2918 Roo.form.Action.Load = function(form, options){
2919 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
2920 this.reader = this.form.reader;
2923 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
2928 Roo.Ajax.request(Roo.apply(
2929 this.createCallback(), {
2930 method:this.getMethod(),
2931 url:this.getUrl(false),
2932 params:this.getParams()
2936 success : function(response){
2938 var result = this.processResponse(response);
2939 if(result === true || !result.success || !result.data){
2940 this.failureType = Roo.form.Action.LOAD_FAILURE;
2941 this.form.afterAction(this, false);
2944 this.form.clearInvalid();
2945 this.form.setValues(result.data);
2946 this.form.afterAction(this, true);
2949 handleResponse : function(response){
2950 if(this.form.reader){
2951 var rs = this.form.reader.read(response);
2952 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
2954 success : rs.success,
2958 return Roo.decode(response.responseText);
2962 Roo.form.Action.ACTION_TYPES = {
2963 'load' : Roo.form.Action.Load,
2964 'submit' : Roo.form.Action.Submit
2973 * @class Roo.bootstrap.Form
2974 * @extends Roo.bootstrap.Component
2975 * Bootstrap Form class
2976 * @cfg {String} method GET | POST (default POST)
2977 * @cfg {String} labelAlign top | left (default top)
2978 * @cfg {String} align left | right - for navbars
2983 * @param {Object} config The config object
2987 Roo.bootstrap.Form = function(config){
2988 Roo.bootstrap.Form.superclass.constructor.call(this, config);
2991 * @event clientvalidation
2992 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
2993 * @param {Form} this
2994 * @param {Boolean} valid true if the form has passed client-side validation
2996 clientvalidation: true,
2998 * @event beforeaction
2999 * Fires before any action is performed. Return false to cancel the action.
3000 * @param {Form} this
3001 * @param {Action} action The action to be performed
3005 * @event actionfailed
3006 * Fires when an action fails.
3007 * @param {Form} this
3008 * @param {Action} action The action that failed
3010 actionfailed : true,
3012 * @event actioncomplete
3013 * Fires when an action is completed.
3014 * @param {Form} this
3015 * @param {Action} action The action that completed
3017 actioncomplete : true
3022 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
3025 * @cfg {String} method
3026 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
3031 * The URL to use for form actions if one isn't supplied in the action options.
3034 * @cfg {Boolean} fileUpload
3035 * Set to true if this form is a file upload.
3039 * @cfg {Object} baseParams
3040 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
3044 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
3048 * @cfg {Sting} align (left|right) for navbar forms
3053 activeAction : null,
3056 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3057 * element by passing it or its id or mask the form itself by passing in true.
3060 waitMsgTarget : false,
3065 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3066 * element by passing it or its id or mask the form itself by passing in true.
3070 getAutoCreate : function(){
3074 method : this.method || 'POST',
3075 id : this.id || Roo.id(),
3078 if (this.parent().xtype.match(/^Nav/)) {
3079 cfg.cls = 'navbar-form navbar-' + this.align;
3083 if (this.labelAlign == 'left' ) {
3084 cfg.cls += ' form-horizontal';
3090 initEvents : function()
3092 this.el.on('submit', this.onSubmit, this);
3097 onSubmit : function(e){
3102 * Returns true if client-side validation on the form is successful.
3105 isValid : function(){
3106 var items = this.getItems();
3108 items.each(function(f){
3117 * Returns true if any fields in this form have changed since their original load.
3120 isDirty : function(){
3122 var items = this.getItems();
3123 items.each(function(f){
3133 * Performs a predefined action (submit or load) or custom actions you define on this form.
3134 * @param {String} actionName The name of the action type
3135 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
3136 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
3137 * accept other config options):
3139 Property Type Description
3140 ---------------- --------------- ----------------------------------------------------------------------------------
3141 url String The url for the action (defaults to the form's url)
3142 method String The form method to use (defaults to the form's method, or POST if not defined)
3143 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
3144 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
3145 validate the form on the client (defaults to false)
3147 * @return {BasicForm} this
3149 doAction : function(action, options){
3150 if(typeof action == 'string'){
3151 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
3153 if(this.fireEvent('beforeaction', this, action) !== false){
3154 this.beforeAction(action);
3155 action.run.defer(100, action);
3161 beforeAction : function(action){
3162 var o = action.options;
3164 // not really supported yet.. ??
3166 //if(this.waitMsgTarget === true){
3167 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
3168 //}else if(this.waitMsgTarget){
3169 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
3170 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
3172 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
3178 afterAction : function(action, success){
3179 this.activeAction = null;
3180 var o = action.options;
3182 //if(this.waitMsgTarget === true){
3184 //}else if(this.waitMsgTarget){
3185 // this.waitMsgTarget.unmask();
3187 // Roo.MessageBox.updateProgress(1);
3188 // Roo.MessageBox.hide();
3195 Roo.callback(o.success, o.scope, [this, action]);
3196 this.fireEvent('actioncomplete', this, action);
3200 // failure condition..
3201 // we have a scenario where updates need confirming.
3202 // eg. if a locking scenario exists..
3203 // we look for { errors : { needs_confirm : true }} in the response.
3205 (typeof(action.result) != 'undefined') &&
3206 (typeof(action.result.errors) != 'undefined') &&
3207 (typeof(action.result.errors.needs_confirm) != 'undefined')
3210 Roo.log("not supported yet");
3213 Roo.MessageBox.confirm(
3214 "Change requires confirmation",
3215 action.result.errorMsg,
3220 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
3230 Roo.callback(o.failure, o.scope, [this, action]);
3231 // show an error message if no failed handler is set..
3232 if (!this.hasListener('actionfailed')) {
3233 Roo.log("need to add dialog support");
3235 Roo.MessageBox.alert("Error",
3236 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
3237 action.result.errorMsg :
3238 "Saving Failed, please check your entries or try again"
3243 this.fireEvent('actionfailed', this, action);
3248 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
3249 * @param {String} id The value to search for
3252 findField : function(id){
3253 var items = this.getItems();
3254 var field = items.get(id);
3256 items.each(function(f){
3257 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
3264 return field || null;
3267 * Mark fields in this form invalid in bulk.
3268 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
3269 * @return {BasicForm} this
3271 markInvalid : function(errors){
3272 if(errors instanceof Array){
3273 for(var i = 0, len = errors.length; i < len; i++){
3274 var fieldError = errors[i];
3275 var f = this.findField(fieldError.id);
3277 f.markInvalid(fieldError.msg);
3283 if(typeof errors[id] != 'function' && (field = this.findField(id))){
3284 field.markInvalid(errors[id]);
3288 //Roo.each(this.childForms || [], function (f) {
3289 // f.markInvalid(errors);
3296 * Set values for fields in this form in bulk.
3297 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
3298 * @return {BasicForm} this
3300 setValues : function(values){
3301 if(values instanceof Array){ // array of objects
3302 for(var i = 0, len = values.length; i < len; i++){
3304 var f = this.findField(v.id);
3306 f.setValue(v.value);
3307 if(this.trackResetOnLoad){
3308 f.originalValue = f.getValue();
3312 }else{ // object hash
3315 if(typeof values[id] != 'function' && (field = this.findField(id))){
3317 if (field.setFromData &&
3319 field.displayField &&
3320 // combos' with local stores can
3321 // be queried via setValue()
3322 // to set their value..
3323 (field.store && !field.store.isLocal)
3327 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
3328 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
3329 field.setFromData(sd);
3332 field.setValue(values[id]);
3336 if(this.trackResetOnLoad){
3337 field.originalValue = field.getValue();
3343 //Roo.each(this.childForms || [], function (f) {
3344 // f.setValues(values);
3351 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
3352 * they are returned as an array.
3353 * @param {Boolean} asString
3356 getValues : function(asString){
3357 //if (this.childForms) {
3358 // copy values from the child forms
3359 // Roo.each(this.childForms, function (f) {
3360 // this.setValues(f.getValues());
3366 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
3367 if(asString === true){
3370 return Roo.urlDecode(fs);
3374 * Returns the fields in this form as an object with key/value pairs.
3375 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
3378 getFieldValues : function(with_hidden)
3380 var items = this.getItems();
3382 items.each(function(f){
3386 var v = f.getValue();
3387 if (f.inputType =='radio') {
3388 if (typeof(ret[f.getName()]) == 'undefined') {
3389 ret[f.getName()] = ''; // empty..
3392 if (!f.el.dom.checked) {
3400 // not sure if this supported any more..
3401 if ((typeof(v) == 'object') && f.getRawValue) {
3402 v = f.getRawValue() ; // dates..
3404 // combo boxes where name != hiddenName...
3405 if (f.name != f.getName()) {
3406 ret[f.name] = f.getRawValue();
3408 ret[f.getName()] = v;
3415 * Clears all invalid messages in this form.
3416 * @return {BasicForm} this
3418 clearInvalid : function(){
3419 var items = this.getItems();
3421 items.each(function(f){
3432 * @return {BasicForm} this
3435 var items = this.getItems();
3436 items.each(function(f){
3440 Roo.each(this.childForms || [], function (f) {
3447 getItems : function()
3449 var r=new Roo.util.MixedCollection(false, function(o){
3450 return o.id || (o.id = Roo.id());
3452 var iter = function(el) {
3459 Roo.each(el.items,function(e) {
3478 * Ext JS Library 1.1.1
3479 * Copyright(c) 2006-2007, Ext JS, LLC.
3481 * Originally Released Under LGPL - original licence link has changed is not relivant.
3484 * <script type="text/javascript">
3487 * @class Roo.form.VTypes
3488 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
3491 Roo.form.VTypes = function(){
3492 // closure these in so they are only created once.
3493 var alpha = /^[a-zA-Z_]+$/;
3494 var alphanum = /^[a-zA-Z0-9_]+$/;
3495 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
3496 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
3498 // All these messages and functions are configurable
3501 * The function used to validate email addresses
3502 * @param {String} value The email address
3504 'email' : function(v){
3505 return email.test(v);
3508 * The error text to display when the email validation function returns false
3511 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
3513 * The keystroke filter mask to be applied on email input
3516 'emailMask' : /[a-z0-9_\.\-@]/i,
3519 * The function used to validate URLs
3520 * @param {String} value The URL
3522 'url' : function(v){
3526 * The error text to display when the url validation function returns false
3529 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
3532 * The function used to validate alpha values
3533 * @param {String} value The value
3535 'alpha' : function(v){
3536 return alpha.test(v);
3539 * The error text to display when the alpha validation function returns false
3542 'alphaText' : 'This field should only contain letters and _',
3544 * The keystroke filter mask to be applied on alpha input
3547 'alphaMask' : /[a-z_]/i,
3550 * The function used to validate alphanumeric values
3551 * @param {String} value The value
3553 'alphanum' : function(v){
3554 return alphanum.test(v);
3557 * The error text to display when the alphanumeric validation function returns false
3560 'alphanumText' : 'This field should only contain letters, numbers and _',
3562 * The keystroke filter mask to be applied on alphanumeric input
3565 'alphanumMask' : /[a-z0-9_]/i
3575 * @class Roo.bootstrap.Input
3576 * @extends Roo.bootstrap.Component
3577 * Bootstrap Input class
3578 * @cfg {Boolean} disabled is it disabled
3579 * @cfg {String} fieldLabel - the label associated
3580 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3581 * @cfg {String} name name of the input
3582 * @cfg {string} fieldLabel - the label associated
3583 * @cfg {string} inputType - input / file submit ...
3584 * @cfg {string} placeholder - placeholder to put in text.
3585 * @cfg {string} before - input group add on before
3586 * @cfg {string} after - input group add on after
3587 * @cfg {string} size - (lg|sm) or leave empty..
3588 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3589 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3590 * @cfg {Number} md colspan out of 12 for computer-sized screens
3591 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3592 * @cfg {string} value default value of the input
3593 * @cfg {Number} labelWidth set the width of label (0-12)
3594 * @cfg {Boolean} checked initial checkbox
3595 * @cfg {String} labelAlign (top|left)
3596 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
3600 * Create a new Input
3601 * @param {Object} config The config object
3604 Roo.bootstrap.Input = function(config){
3605 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3610 * Fires when this field receives input focus.
3611 * @param {Roo.form.Field} this
3616 * Fires when this field loses input focus.
3617 * @param {Roo.form.Field} this
3622 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3623 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3624 * @param {Roo.form.Field} this
3625 * @param {Roo.EventObject} e The event object
3630 * Fires just before the field blurs if the field value has changed.
3631 * @param {Roo.form.Field} this
3632 * @param {Mixed} newValue The new value
3633 * @param {Mixed} oldValue The original value
3638 * Fires after the field has been marked as invalid.
3639 * @param {Roo.form.Field} this
3640 * @param {String} msg The validation message
3645 * Fires after the field has been validated with no errors.
3646 * @param {Roo.form.Field} this
3651 * Fires after the key up
3652 * @param {Roo.form.Field} this
3653 * @param {Roo.EventObject} e The event Object
3658 * Fires when the checkbox or radio is checked or unchecked.
3659 * @param {Roo.bootstrap.Input} this This input
3660 * @param {Boolean} checked The new checked value
3666 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3668 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3669 automatic validation (defaults to "keyup").
3671 validationEvent : "keyup",
3673 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3675 validateOnBlur : true,
3677 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3679 validationDelay : 250,
3681 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3683 focusClass : "x-form-focus", // not needed???
3687 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3689 invalidClass : "has-error",
3692 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3694 selectOnFocus : false,
3697 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3701 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3706 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3708 disableKeyFilter : false,
3711 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3715 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3719 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3721 blankText : "This field is required",
3724 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3728 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3730 maxLength : Number.MAX_VALUE,
3732 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3734 minLengthText : "The minimum length for this field is {0}",
3736 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3738 maxLengthText : "The maximum length for this field is {0}",
3742 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3743 * If available, this function will be called only after the basic validators all return true, and will be passed the
3744 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3748 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3749 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3750 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
3754 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3778 parentLabelAlign : function()
3781 while (parent.parent()) {
3782 parent = parent.parent();
3783 if (typeof(parent.labelAlign) !='undefined') {
3784 return parent.labelAlign;
3791 getAutoCreate : function(){
3793 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
3799 if(this.inputType != 'hidden'){
3800 cfg.cls = 'form-group' //input-group
3806 type : this.inputType,
3808 cls : 'form-control',
3809 placeholder : this.placeholder || ''
3813 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
3814 input.maxLength = this.maxLength;
3817 if (this.disabled) {
3818 input.disabled=true;
3822 input.checked = this.checked;
3826 input.name = this.name;
3829 input.cls += ' input-' + this.size;
3832 ['xs','sm','md','lg'].map(function(size){
3833 if (settings[size]) {
3834 cfg.cls += ' col-' + size + '-' + settings[size];
3838 var inputblock = input;
3840 if (this.before || this.after) {
3843 cls : 'input-group',
3847 inputblock.cn.push({
3849 cls : 'input-group-addon',
3853 inputblock.cn.push(input);
3855 inputblock.cn.push({
3857 cls : 'input-group-addon',
3864 if (align ==='left' && this.fieldLabel.length) {
3865 Roo.log("left and has label");
3871 cls : 'control-label col-sm-' + this.labelWidth,
3872 html : this.fieldLabel
3876 cls : "col-sm-" + (12 - this.labelWidth),
3883 } else if ( this.fieldLabel.length) {
3889 //cls : 'input-group-addon',
3890 html : this.fieldLabel
3900 Roo.log(" no label && no align");
3914 * return the real input element.
3916 inputEl: function ()
3918 return this.el.select('input.form-control',true).first();
3920 setDisabled : function(v)
3922 var i = this.inputEl().dom;
3924 i.removeAttribute('disabled');
3928 i.setAttribute('disabled','true');
3930 initEvents : function()
3933 this.inputEl().on("keydown" , this.fireKey, this);
3934 this.inputEl().on("focus", this.onFocus, this);
3935 this.inputEl().on("blur", this.onBlur, this);
3937 this.inputEl().on('click', this.onClick, this);
3939 this.inputEl().relayEvent('keyup', this);
3941 // reference to original value for reset
3942 this.originalValue = this.getValue();
3943 //Roo.form.TextField.superclass.initEvents.call(this);
3944 if(this.validationEvent == 'keyup'){
3945 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
3946 this.inputEl().on('keyup', this.filterValidation, this);
3948 else if(this.validationEvent !== false){
3949 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
3952 if(this.selectOnFocus){
3953 this.on("focus", this.preFocus, this);
3956 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
3957 this.inputEl().on("keypress", this.filterKeys, this);
3960 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
3961 this.el.on("click", this.autoSize, this);
3964 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
3965 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
3969 filterValidation : function(e){
3970 if(!e.isNavKeyPress()){
3971 this.validationTask.delay(this.validationDelay);
3975 * Validates the field value
3976 * @return {Boolean} True if the value is valid, else false
3978 validate : function(){
3979 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
3980 if(this.disabled || this.validateValue(this.getRawValue())){
3981 this.clearInvalid();
3989 * Validates a value according to the field's validation rules and marks the field as invalid
3990 * if the validation fails
3991 * @param {Mixed} value The value to validate
3992 * @return {Boolean} True if the value is valid, else false
3994 validateValue : function(value){
3995 if(value.length < 1) { // if it's blank
3996 if(this.allowBlank){
3997 this.clearInvalid();
4000 this.markInvalid(this.blankText);
4004 if(value.length < this.minLength){
4005 this.markInvalid(String.format(this.minLengthText, this.minLength));
4008 if(value.length > this.maxLength){
4009 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
4013 var vt = Roo.form.VTypes;
4014 if(!vt[this.vtype](value, this)){
4015 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
4019 if(typeof this.validator == "function"){
4020 var msg = this.validator(value);
4022 this.markInvalid(msg);
4026 if(this.regex && !this.regex.test(value)){
4027 this.markInvalid(this.regexText);
4036 fireKey : function(e){
4037 //Roo.log('field ' + e.getKey());
4038 if(e.isNavKeyPress()){
4039 this.fireEvent("specialkey", this, e);
4042 focus : function (selectText){
4044 this.inputEl().focus();
4045 if(selectText === true){
4046 this.inputEl().dom.select();
4052 onFocus : function(){
4053 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4054 // this.el.addClass(this.focusClass);
4057 this.hasFocus = true;
4058 this.startValue = this.getValue();
4059 this.fireEvent("focus", this);
4063 beforeBlur : Roo.emptyFn,
4067 onBlur : function(){
4069 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4070 //this.el.removeClass(this.focusClass);
4072 this.hasFocus = false;
4073 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
4076 var v = this.getValue();
4077 if(String(v) !== String(this.startValue)){
4078 this.fireEvent('change', this, v, this.startValue);
4080 this.fireEvent("blur", this);
4084 * Resets the current field value to the originally loaded value and clears any validation messages
4087 this.setValue(this.originalValue);
4088 this.clearInvalid();
4091 * Returns the name of the field
4092 * @return {Mixed} name The name field
4094 getName: function(){
4098 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
4099 * @return {Mixed} value The field value
4101 getValue : function(){
4102 if(this.inputType != 'checkbox' && this.inputType != 'radio'){
4103 return this.inputEl().getValue();
4106 return this.getGroupValue();
4109 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
4110 * @return {Mixed} value The field value
4112 getRawValue : function(){
4113 var v = this.inputEl().getValue();
4119 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
4120 * @param {Mixed} value The value to set
4122 setRawValue : function(v){
4123 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4126 selectText : function(start, end){
4127 var v = this.getRawValue();
4129 start = start === undefined ? 0 : start;
4130 end = end === undefined ? v.length : end;
4131 var d = this.inputEl().dom;
4132 if(d.setSelectionRange){
4133 d.setSelectionRange(start, end);
4134 }else if(d.createTextRange){
4135 var range = d.createTextRange();
4136 range.moveStart("character", start);
4137 range.moveEnd("character", v.length-end);
4144 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
4145 * @param {Mixed} value The value to set
4147 setValue : function(v){
4150 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4156 processValue : function(value){
4157 if(this.stripCharsRe){
4158 var newValue = value.replace(this.stripCharsRe, '');
4159 if(newValue !== value){
4160 this.setRawValue(newValue);
4167 preFocus : function(){
4169 if(this.selectOnFocus){
4170 this.inputEl().dom.select();
4173 filterKeys : function(e){
4175 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
4178 var c = e.getCharCode(), cc = String.fromCharCode(c);
4179 if(Roo.isIE && (e.isSpecialKey() || !cc)){
4182 if(!this.maskRe.test(cc)){
4187 * Clear any invalid styles/messages for this field
4189 clearInvalid : function(){
4191 if(!this.el || this.preventMark){ // not rendered
4194 this.el.removeClass(this.invalidClass);
4196 switch(this.msgTarget){
4198 this.el.dom.qtip = '';
4201 this.el.dom.title = '';
4205 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
4210 this.errorIcon.dom.qtip = '';
4211 this.errorIcon.hide();
4212 this.un('resize', this.alignErrorIcon, this);
4216 var t = Roo.getDom(this.msgTarget);
4218 t.style.display = 'none';
4222 this.fireEvent('valid', this);
4225 * Mark this field as invalid
4226 * @param {String} msg The validation message
4228 markInvalid : function(msg){
4229 if(!this.el || this.preventMark){ // not rendered
4232 this.el.addClass(this.invalidClass);
4234 msg = msg || this.invalidText;
4235 switch(this.msgTarget){
4237 this.el.dom.qtip = msg;
4238 this.el.dom.qclass = 'x-form-invalid-tip';
4239 if(Roo.QuickTips){ // fix for floating editors interacting with DND
4240 Roo.QuickTips.enable();
4244 this.el.dom.title = msg;
4248 var elp = this.el.findParent('.x-form-element', 5, true);
4249 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
4250 this.errorEl.setWidth(elp.getWidth(true)-20);
4252 this.errorEl.update(msg);
4253 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
4256 if(!this.errorIcon){
4257 var elp = this.el.findParent('.x-form-element', 5, true);
4258 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
4260 this.alignErrorIcon();
4261 this.errorIcon.dom.qtip = msg;
4262 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
4263 this.errorIcon.show();
4264 this.on('resize', this.alignErrorIcon, this);
4267 var t = Roo.getDom(this.msgTarget);
4269 t.style.display = this.msgDisplay;
4273 this.fireEvent('invalid', this, msg);
4276 SafariOnKeyDown : function(event)
4278 // this is a workaround for a password hang bug on chrome/ webkit.
4280 var isSelectAll = false;
4282 if(this.inputEl().dom.selectionEnd > 0){
4283 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
4285 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
4286 event.preventDefault();
4291 if(isSelectAll){ // backspace and delete key
4293 event.preventDefault();
4294 // this is very hacky as keydown always get's upper case.
4296 var cc = String.fromCharCode(event.getCharCode());
4297 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
4304 getGroupValue : function()
4306 if(typeof(this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true)) == 'undefined'){
4310 return this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true).value;
4313 onClick : function()
4315 if(this.inputType != 'checkbox' && this.inputType != 'radio'){
4319 this.setChecked(!this.checked);
4322 setChecked : function(state,suppressEvent)
4325 this.checked = state;
4327 if(suppressEvent !== true){
4328 this.fireEvent('check', this, state);
4331 this.inputEl().dom.value = state ? this.value : this.valueOff;
4345 * @class Roo.bootstrap.TextArea
4346 * @extends Roo.bootstrap.Input
4347 * Bootstrap TextArea class
4348 * @cfg {Number} cols Specifies the visible width of a text area
4349 * @cfg {Number} rows Specifies the visible number of lines in a text area
4350 * @cfg {Number} readOnly Specifies that a text area should be read-only
4351 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
4352 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
4353 * @cfg {string} html text
4356 * Create a new TextArea
4357 * @param {Object} config The config object
4360 Roo.bootstrap.TextArea = function(config){
4361 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
4365 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
4375 getAutoCreate : function(){
4377 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4388 value : this.value || '',
4389 html: this.html || '',
4390 cls : 'form-control',
4391 placeholder : this.placeholder || ''
4395 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4396 input.maxLength = this.maxLength;
4400 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
4404 input.cols = this.cols;
4407 if (this.readOnly) {
4408 input.readonly = true;
4412 input.name = this.name;
4416 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
4420 ['xs','sm','md','lg'].map(function(size){
4421 if (settings[size]) {
4422 cfg.cls += ' col-' + size + '-' + settings[size];
4426 var inputblock = input;
4428 if (this.before || this.after) {
4431 cls : 'input-group',
4435 inputblock.cn.push({
4437 cls : 'input-group-addon',
4441 inputblock.cn.push(input);
4443 inputblock.cn.push({
4445 cls : 'input-group-addon',
4452 if (align ==='left' && this.fieldLabel.length) {
4453 Roo.log("left and has label");
4459 cls : 'control-label col-sm-' + this.labelWidth,
4460 html : this.fieldLabel
4464 cls : "col-sm-" + (12 - this.labelWidth),
4471 } else if ( this.fieldLabel.length) {
4477 //cls : 'input-group-addon',
4478 html : this.fieldLabel
4488 Roo.log(" no label && no align");
4498 if (this.disabled) {
4499 input.disabled=true;
4506 * return the real textarea element.
4508 inputEl: function ()
4510 return this.el.select('textarea.form-control',true).first();
4518 * trigger field - base class for combo..
4523 * @class Roo.bootstrap.TriggerField
4524 * @extends Roo.bootstrap.Input
4525 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
4526 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
4527 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
4528 * for which you can provide a custom implementation. For example:
4530 var trigger = new Roo.bootstrap.TriggerField();
4531 trigger.onTriggerClick = myTriggerFn;
4532 trigger.applyTo('my-field');
4535 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
4536 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
4537 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
4538 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
4540 * Create a new TriggerField.
4541 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
4542 * to the base TextField)
4544 Roo.bootstrap.TriggerField = function(config){
4545 this.mimicing = false;
4546 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
4549 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
4551 * @cfg {String} triggerClass A CSS class to apply to the trigger
4554 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
4558 /** @cfg {Boolean} grow @hide */
4559 /** @cfg {Number} growMin @hide */
4560 /** @cfg {Number} growMax @hide */
4566 autoSize: Roo.emptyFn,
4573 actionMode : 'wrap',
4577 getAutoCreate : function(){
4579 var parent = this.parent();
4581 var align = this.parentLabelAlign();
4586 cls: 'form-group' //input-group
4593 type : this.inputType,
4594 cls : 'form-control',
4595 autocomplete: 'off',
4596 placeholder : this.placeholder || ''
4600 input.name = this.name;
4603 input.cls += ' input-' + this.size;
4606 cls: 'combobox-container input-group',
4611 cls: 'form-hidden-field'
4616 cls : 'typeahead typeahead-long dropdown-menu',
4617 style : 'display:none'
4621 cls : 'input-group-addon btn dropdown-toggle',
4629 cls: 'combobox-clear',
4646 if (align ==='left' && this.fieldLabel.length) {
4650 Roo.log("left and has label");
4656 cls : 'col-sm-2 control-label',
4657 html : this.fieldLabel
4668 } else if ( this.fieldLabel.length) {
4674 //cls : 'input-group-addon',
4675 html : this.fieldLabel
4685 Roo.log(" no label && no align");
4692 ['xs','sm','md','lg'].map(function(size){
4693 if (settings[size]) {
4694 cfg.cls += ' col-' + size + '-' + settings[size];
4700 if (this.disabled) {
4701 input.disabled=true;
4710 onResize : function(w, h){
4711 Roo.boostrap.TriggerField.superclass.onResize.apply(this, arguments);
4712 if(typeof w == 'number'){
4713 var x = w - this.trigger.getWidth();
4714 this.inputEl().setWidth(this.adjustWidth('input', x));
4715 this.trigger.setStyle('left', x+'px');
4720 adjustSize : Roo.BoxComponent.prototype.adjustSize,
4723 getResizeEl : function(){
4724 return this.inputEl();
4728 getPositionEl : function(){
4729 return this.inputEl();
4733 alignErrorIcon : function(){
4734 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
4738 initEvents : function(){
4740 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
4741 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
4743 this.trigger = this.el.select('span.dropdown-toggle',true).first();
4744 if(this.hideTrigger){
4745 this.trigger.setDisplayed(false);
4747 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
4748 //this.trigger.addClassOnOver('x-form-trigger-over');
4749 //this.trigger.addClassOnClick('x-form-trigger-click');
4752 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
4757 initTrigger : function(){
4762 onDestroy : function(){
4764 this.trigger.removeAllListeners();
4765 // this.trigger.remove();
4768 // this.wrap.remove();
4770 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
4774 onFocus : function(){
4775 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
4778 this.wrap.addClass('x-trigger-wrap-focus');
4779 this.mimicing = true;
4780 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
4781 if(this.monitorTab){
4782 this.el.on("keydown", this.checkTab, this);
4789 checkTab : function(e){
4790 if(e.getKey() == e.TAB){
4796 onBlur : function(){
4801 mimicBlur : function(e, t){
4803 if(!this.wrap.contains(t) && this.validateBlur()){
4810 triggerBlur : function(){
4811 this.mimicing = false;
4812 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
4813 if(this.monitorTab){
4814 this.el.un("keydown", this.checkTab, this);
4816 //this.wrap.removeClass('x-trigger-wrap-focus');
4817 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
4821 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
4822 validateBlur : function(e, t){
4827 onDisable : function(){
4828 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
4830 // this.wrap.addClass('x-item-disabled');
4835 onEnable : function(){
4836 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
4838 // this.el.removeClass('x-item-disabled');
4843 onShow : function(){
4844 var ae = this.getActionEl();
4847 ae.dom.style.display = '';
4848 ae.dom.style.visibility = 'visible';
4854 onHide : function(){
4855 var ae = this.getActionEl();
4856 ae.dom.style.display = 'none';
4860 * The function that should handle the trigger's click event. This method does nothing by default until overridden
4861 * by an implementing function.
4863 * @param {EventObject} e
4865 onTriggerClick : Roo.emptyFn
4869 * Ext JS Library 1.1.1
4870 * Copyright(c) 2006-2007, Ext JS, LLC.
4872 * Originally Released Under LGPL - original licence link has changed is not relivant.
4875 * <script type="text/javascript">
4880 * @class Roo.data.SortTypes
4882 * Defines the default sorting (casting?) comparison functions used when sorting data.
4884 Roo.data.SortTypes = {
4886 * Default sort that does nothing
4887 * @param {Mixed} s The value being converted
4888 * @return {Mixed} The comparison value
4895 * The regular expression used to strip tags
4899 stripTagsRE : /<\/?[^>]+>/gi,
4902 * Strips all HTML tags to sort on text only
4903 * @param {Mixed} s The value being converted
4904 * @return {String} The comparison value
4906 asText : function(s){
4907 return String(s).replace(this.stripTagsRE, "");
4911 * Strips all HTML tags to sort on text only - Case insensitive
4912 * @param {Mixed} s The value being converted
4913 * @return {String} The comparison value
4915 asUCText : function(s){
4916 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4920 * Case insensitive string
4921 * @param {Mixed} s The value being converted
4922 * @return {String} The comparison value
4924 asUCString : function(s) {
4925 return String(s).toUpperCase();
4930 * @param {Mixed} s The value being converted
4931 * @return {Number} The comparison value
4933 asDate : function(s) {
4937 if(s instanceof Date){
4940 return Date.parse(String(s));
4945 * @param {Mixed} s The value being converted
4946 * @return {Float} The comparison value
4948 asFloat : function(s) {
4949 var val = parseFloat(String(s).replace(/,/g, ""));
4950 if(isNaN(val)) val = 0;
4956 * @param {Mixed} s The value being converted
4957 * @return {Number} The comparison value
4959 asInt : function(s) {
4960 var val = parseInt(String(s).replace(/,/g, ""));
4961 if(isNaN(val)) val = 0;
4966 * Ext JS Library 1.1.1
4967 * Copyright(c) 2006-2007, Ext JS, LLC.
4969 * Originally Released Under LGPL - original licence link has changed is not relivant.
4972 * <script type="text/javascript">
4976 * @class Roo.data.Record
4977 * Instances of this class encapsulate both record <em>definition</em> information, and record
4978 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4979 * to access Records cached in an {@link Roo.data.Store} object.<br>
4981 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4982 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4985 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4987 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4988 * {@link #create}. The parameters are the same.
4989 * @param {Array} data An associative Array of data values keyed by the field name.
4990 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4991 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4992 * not specified an integer id is generated.
4994 Roo.data.Record = function(data, id){
4995 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
5000 * Generate a constructor for a specific record layout.
5001 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
5002 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
5003 * Each field definition object may contain the following properties: <ul>
5004 * <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,
5005 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
5006 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
5007 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
5008 * is being used, then this is a string containing the javascript expression to reference the data relative to
5009 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
5010 * to the data item relative to the record element. If the mapping expression is the same as the field name,
5011 * this may be omitted.</p></li>
5012 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
5013 * <ul><li>auto (Default, implies no conversion)</li>
5018 * <li>date</li></ul></p></li>
5019 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
5020 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
5021 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
5022 * by the Reader into an object that will be stored in the Record. It is passed the
5023 * following parameters:<ul>
5024 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
5026 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
5028 * <br>usage:<br><pre><code>
5029 var TopicRecord = Roo.data.Record.create(
5030 {name: 'title', mapping: 'topic_title'},
5031 {name: 'author', mapping: 'username'},
5032 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
5033 {name: 'lastPost', mapping: 'post_time', type: 'date'},
5034 {name: 'lastPoster', mapping: 'user2'},
5035 {name: 'excerpt', mapping: 'post_text'}
5038 var myNewRecord = new TopicRecord({
5039 title: 'Do my job please',
5042 lastPost: new Date(),
5043 lastPoster: 'Animal',
5044 excerpt: 'No way dude!'
5046 myStore.add(myNewRecord);
5051 Roo.data.Record.create = function(o){
5053 f.superclass.constructor.apply(this, arguments);
5055 Roo.extend(f, Roo.data.Record);
5056 var p = f.prototype;
5057 p.fields = new Roo.util.MixedCollection(false, function(field){
5060 for(var i = 0, len = o.length; i < len; i++){
5061 p.fields.add(new Roo.data.Field(o[i]));
5063 f.getField = function(name){
5064 return p.fields.get(name);
5069 Roo.data.Record.AUTO_ID = 1000;
5070 Roo.data.Record.EDIT = 'edit';
5071 Roo.data.Record.REJECT = 'reject';
5072 Roo.data.Record.COMMIT = 'commit';
5074 Roo.data.Record.prototype = {
5076 * Readonly flag - true if this record has been modified.
5085 join : function(store){
5090 * Set the named field to the specified value.
5091 * @param {String} name The name of the field to set.
5092 * @param {Object} value The value to set the field to.
5094 set : function(name, value){
5095 if(this.data[name] == value){
5102 if(typeof this.modified[name] == 'undefined'){
5103 this.modified[name] = this.data[name];
5105 this.data[name] = value;
5106 if(!this.editing && this.store){
5107 this.store.afterEdit(this);
5112 * Get the value of the named field.
5113 * @param {String} name The name of the field to get the value of.
5114 * @return {Object} The value of the field.
5116 get : function(name){
5117 return this.data[name];
5121 beginEdit : function(){
5122 this.editing = true;
5127 cancelEdit : function(){
5128 this.editing = false;
5129 delete this.modified;
5133 endEdit : function(){
5134 this.editing = false;
5135 if(this.dirty && this.store){
5136 this.store.afterEdit(this);
5141 * Usually called by the {@link Roo.data.Store} which owns the Record.
5142 * Rejects all changes made to the Record since either creation, or the last commit operation.
5143 * Modified fields are reverted to their original values.
5145 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5146 * of reject operations.
5148 reject : function(){
5149 var m = this.modified;
5151 if(typeof m[n] != "function"){
5152 this.data[n] = m[n];
5156 delete this.modified;
5157 this.editing = false;
5159 this.store.afterReject(this);
5164 * Usually called by the {@link Roo.data.Store} which owns the Record.
5165 * Commits all changes made to the Record since either creation, or the last commit operation.
5167 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5168 * of commit operations.
5170 commit : function(){
5172 delete this.modified;
5173 this.editing = false;
5175 this.store.afterCommit(this);
5180 hasError : function(){
5181 return this.error != null;
5185 clearError : function(){
5190 * Creates a copy of this record.
5191 * @param {String} id (optional) A new record id if you don't want to use this record's id
5194 copy : function(newId) {
5195 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
5199 * Ext JS Library 1.1.1
5200 * Copyright(c) 2006-2007, Ext JS, LLC.
5202 * Originally Released Under LGPL - original licence link has changed is not relivant.
5205 * <script type="text/javascript">
5211 * @class Roo.data.Store
5212 * @extends Roo.util.Observable
5213 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
5214 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
5216 * 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
5217 * has no knowledge of the format of the data returned by the Proxy.<br>
5219 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
5220 * instances from the data object. These records are cached and made available through accessor functions.
5222 * Creates a new Store.
5223 * @param {Object} config A config object containing the objects needed for the Store to access data,
5224 * and read the data into Records.
5226 Roo.data.Store = function(config){
5227 this.data = new Roo.util.MixedCollection(false);
5228 this.data.getKey = function(o){
5231 this.baseParams = {};
5238 "multisort" : "_multisort"
5241 if(config && config.data){
5242 this.inlineData = config.data;
5246 Roo.apply(this, config);
5248 if(this.reader){ // reader passed
5249 this.reader = Roo.factory(this.reader, Roo.data);
5250 this.reader.xmodule = this.xmodule || false;
5251 if(!this.recordType){
5252 this.recordType = this.reader.recordType;
5254 if(this.reader.onMetaChange){
5255 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
5259 if(this.recordType){
5260 this.fields = this.recordType.prototype.fields;
5266 * @event datachanged
5267 * Fires when the data cache has changed, and a widget which is using this Store
5268 * as a Record cache should refresh its view.
5269 * @param {Store} this
5274 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
5275 * @param {Store} this
5276 * @param {Object} meta The JSON metadata
5281 * Fires when Records have been added to the Store
5282 * @param {Store} this
5283 * @param {Roo.data.Record[]} records The array of Records added
5284 * @param {Number} index The index at which the record(s) were added
5289 * Fires when a Record has been removed from the Store
5290 * @param {Store} this
5291 * @param {Roo.data.Record} record The Record that was removed
5292 * @param {Number} index The index at which the record was removed
5297 * Fires when a Record has been updated
5298 * @param {Store} this
5299 * @param {Roo.data.Record} record The Record that was updated
5300 * @param {String} operation The update operation being performed. Value may be one of:
5302 Roo.data.Record.EDIT
5303 Roo.data.Record.REJECT
5304 Roo.data.Record.COMMIT
5310 * Fires when the data cache has been cleared.
5311 * @param {Store} this
5316 * Fires before a request is made for a new data object. If the beforeload handler returns false
5317 * the load action will be canceled.
5318 * @param {Store} this
5319 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5323 * @event beforeloadadd
5324 * Fires after a new set of Records has been loaded.
5325 * @param {Store} this
5326 * @param {Roo.data.Record[]} records The Records that were loaded
5327 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5329 beforeloadadd : true,
5332 * Fires after a new set of Records has been loaded, before they are added to the store.
5333 * @param {Store} this
5334 * @param {Roo.data.Record[]} records The Records that were loaded
5335 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5336 * @params {Object} return from reader
5340 * @event loadexception
5341 * Fires if an exception occurs in the Proxy during loading.
5342 * Called with the signature of the Proxy's "loadexception" event.
5343 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
5346 * @param {Object} return from JsonData.reader() - success, totalRecords, records
5347 * @param {Object} load options
5348 * @param {Object} jsonData from your request (normally this contains the Exception)
5350 loadexception : true
5354 this.proxy = Roo.factory(this.proxy, Roo.data);
5355 this.proxy.xmodule = this.xmodule || false;
5356 this.relayEvents(this.proxy, ["loadexception"]);
5358 this.sortToggle = {};
5359 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
5361 Roo.data.Store.superclass.constructor.call(this);
5363 if(this.inlineData){
5364 this.loadData(this.inlineData);
5365 delete this.inlineData;
5369 Roo.extend(Roo.data.Store, Roo.util.Observable, {
5371 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
5372 * without a remote query - used by combo/forms at present.
5376 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
5379 * @cfg {Array} data Inline data to be loaded when the store is initialized.
5382 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
5383 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
5386 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
5387 * on any HTTP request
5390 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
5393 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
5397 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
5398 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
5403 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
5404 * loaded or when a record is removed. (defaults to false).
5406 pruneModifiedRecords : false,
5412 * Add Records to the Store and fires the add event.
5413 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
5415 add : function(records){
5416 records = [].concat(records);
5417 for(var i = 0, len = records.length; i < len; i++){
5418 records[i].join(this);
5420 var index = this.data.length;
5421 this.data.addAll(records);
5422 this.fireEvent("add", this, records, index);
5426 * Remove a Record from the Store and fires the remove event.
5427 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
5429 remove : function(record){
5430 var index = this.data.indexOf(record);
5431 this.data.removeAt(index);
5432 if(this.pruneModifiedRecords){
5433 this.modified.remove(record);
5435 this.fireEvent("remove", this, record, index);
5439 * Remove all Records from the Store and fires the clear event.
5441 removeAll : function(){
5443 if(this.pruneModifiedRecords){
5446 this.fireEvent("clear", this);
5450 * Inserts Records to the Store at the given index and fires the add event.
5451 * @param {Number} index The start index at which to insert the passed Records.
5452 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
5454 insert : function(index, records){
5455 records = [].concat(records);
5456 for(var i = 0, len = records.length; i < len; i++){
5457 this.data.insert(index, records[i]);
5458 records[i].join(this);
5460 this.fireEvent("add", this, records, index);
5464 * Get the index within the cache of the passed Record.
5465 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
5466 * @return {Number} The index of the passed Record. Returns -1 if not found.
5468 indexOf : function(record){
5469 return this.data.indexOf(record);
5473 * Get the index within the cache of the Record with the passed id.
5474 * @param {String} id The id of the Record to find.
5475 * @return {Number} The index of the Record. Returns -1 if not found.
5477 indexOfId : function(id){
5478 return this.data.indexOfKey(id);
5482 * Get the Record with the specified id.
5483 * @param {String} id The id of the Record to find.
5484 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
5486 getById : function(id){
5487 return this.data.key(id);
5491 * Get the Record at the specified index.
5492 * @param {Number} index The index of the Record to find.
5493 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
5495 getAt : function(index){
5496 return this.data.itemAt(index);
5500 * Returns a range of Records between specified indices.
5501 * @param {Number} startIndex (optional) The starting index (defaults to 0)
5502 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
5503 * @return {Roo.data.Record[]} An array of Records
5505 getRange : function(start, end){
5506 return this.data.getRange(start, end);
5510 storeOptions : function(o){
5511 o = Roo.apply({}, o);
5514 this.lastOptions = o;
5518 * Loads the Record cache from the configured Proxy using the configured Reader.
5520 * If using remote paging, then the first load call must specify the <em>start</em>
5521 * and <em>limit</em> properties in the options.params property to establish the initial
5522 * position within the dataset, and the number of Records to cache on each read from the Proxy.
5524 * <strong>It is important to note that for remote data sources, loading is asynchronous,
5525 * and this call will return before the new data has been loaded. Perform any post-processing
5526 * in a callback function, or in a "load" event handler.</strong>
5528 * @param {Object} options An object containing properties which control loading options:<ul>
5529 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
5530 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
5531 * passed the following arguments:<ul>
5532 * <li>r : Roo.data.Record[]</li>
5533 * <li>options: Options object from the load call</li>
5534 * <li>success: Boolean success indicator</li></ul></li>
5535 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
5536 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
5539 load : function(options){
5540 options = options || {};
5541 if(this.fireEvent("beforeload", this, options) !== false){
5542 this.storeOptions(options);
5543 var p = Roo.apply(options.params || {}, this.baseParams);
5544 // if meta was not loaded from remote source.. try requesting it.
5545 if (!this.reader.metaFromRemote) {
5548 if(this.sortInfo && this.remoteSort){
5549 var pn = this.paramNames;
5550 p[pn["sort"]] = this.sortInfo.field;
5551 p[pn["dir"]] = this.sortInfo.direction;
5553 if (this.multiSort) {
5554 var pn = this.paramNames;
5555 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
5558 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5563 * Reloads the Record cache from the configured Proxy using the configured Reader and
5564 * the options from the last load operation performed.
5565 * @param {Object} options (optional) An object containing properties which may override the options
5566 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5567 * the most recently used options are reused).
5569 reload : function(options){
5570 this.load(Roo.applyIf(options||{}, this.lastOptions));
5574 // Called as a callback by the Reader during a load operation.
5575 loadRecords : function(o, options, success){
5576 if(!o || success === false){
5577 if(success !== false){
5578 this.fireEvent("load", this, [], options, o);
5580 if(options.callback){
5581 options.callback.call(options.scope || this, [], options, false);
5585 // if data returned failure - throw an exception.
5586 if (o.success === false) {
5587 // show a message if no listener is registered.
5588 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
5589 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
5591 // loadmask wil be hooked into this..
5592 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
5595 var r = o.records, t = o.totalRecords || r.length;
5597 this.fireEvent("beforeloadadd", this, r, options, o);
5599 if(!options || options.add !== true){
5600 if(this.pruneModifiedRecords){
5603 for(var i = 0, len = r.length; i < len; i++){
5607 this.data = this.snapshot;
5608 delete this.snapshot;
5611 this.data.addAll(r);
5612 this.totalLength = t;
5614 this.fireEvent("datachanged", this);
5616 this.totalLength = Math.max(t, this.data.length+r.length);
5619 this.fireEvent("load", this, r, options, o);
5620 if(options.callback){
5621 options.callback.call(options.scope || this, r, options, true);
5627 * Loads data from a passed data block. A Reader which understands the format of the data
5628 * must have been configured in the constructor.
5629 * @param {Object} data The data block from which to read the Records. The format of the data expected
5630 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5631 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5633 loadData : function(o, append){
5634 var r = this.reader.readRecords(o);
5635 this.loadRecords(r, {add: append}, true);
5639 * Gets the number of cached records.
5641 * <em>If using paging, this may not be the total size of the dataset. If the data object
5642 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5643 * the data set size</em>
5645 getCount : function(){
5646 return this.data.length || 0;
5650 * Gets the total number of records in the dataset as returned by the server.
5652 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5653 * the dataset size</em>
5655 getTotalCount : function(){
5656 return this.totalLength || 0;
5660 * Returns the sort state of the Store as an object with two properties:
5662 field {String} The name of the field by which the Records are sorted
5663 direction {String} The sort order, "ASC" or "DESC"
5666 getSortState : function(){
5667 return this.sortInfo;
5671 applySort : function(){
5672 if(this.sortInfo && !this.remoteSort){
5673 var s = this.sortInfo, f = s.field;
5674 var st = this.fields.get(f).sortType;
5675 var fn = function(r1, r2){
5676 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5677 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5679 this.data.sort(s.direction, fn);
5680 if(this.snapshot && this.snapshot != this.data){
5681 this.snapshot.sort(s.direction, fn);
5687 * Sets the default sort column and order to be used by the next load operation.
5688 * @param {String} fieldName The name of the field to sort by.
5689 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5691 setDefaultSort : function(field, dir){
5692 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5697 * If remote sorting is used, the sort is performed on the server, and the cache is
5698 * reloaded. If local sorting is used, the cache is sorted internally.
5699 * @param {String} fieldName The name of the field to sort by.
5700 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5702 sort : function(fieldName, dir){
5703 var f = this.fields.get(fieldName);
5705 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
5707 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
5708 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5713 this.sortToggle[f.name] = dir;
5714 this.sortInfo = {field: f.name, direction: dir};
5715 if(!this.remoteSort){
5717 this.fireEvent("datachanged", this);
5719 this.load(this.lastOptions);
5724 * Calls the specified function for each of the Records in the cache.
5725 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5726 * Returning <em>false</em> aborts and exits the iteration.
5727 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5729 each : function(fn, scope){
5730 this.data.each(fn, scope);
5734 * Gets all records modified since the last commit. Modified records are persisted across load operations
5735 * (e.g., during paging).
5736 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5738 getModifiedRecords : function(){
5739 return this.modified;
5743 createFilterFn : function(property, value, anyMatch){
5744 if(!value.exec){ // not a regex
5745 value = String(value);
5746 if(value.length == 0){
5749 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5752 return value.test(r.data[property]);
5757 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5758 * @param {String} property A field on your records
5759 * @param {Number} start The record index to start at (defaults to 0)
5760 * @param {Number} end The last record index to include (defaults to length - 1)
5761 * @return {Number} The sum
5763 sum : function(property, start, end){
5764 var rs = this.data.items, v = 0;
5766 end = (end || end === 0) ? end : rs.length-1;
5768 for(var i = start; i <= end; i++){
5769 v += (rs[i].data[property] || 0);
5775 * Filter the records by a specified property.
5776 * @param {String} field A field on your records
5777 * @param {String/RegExp} value Either a string that the field
5778 * should start with or a RegExp to test against the field
5779 * @param {Boolean} anyMatch True to match any part not just the beginning
5781 filter : function(property, value, anyMatch){
5782 var fn = this.createFilterFn(property, value, anyMatch);
5783 return fn ? this.filterBy(fn) : this.clearFilter();
5787 * Filter by a function. The specified function will be called with each
5788 * record in this data source. If the function returns true the record is included,
5789 * otherwise it is filtered.
5790 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5791 * @param {Object} scope (optional) The scope of the function (defaults to this)
5793 filterBy : function(fn, scope){
5794 this.snapshot = this.snapshot || this.data;
5795 this.data = this.queryBy(fn, scope||this);
5796 this.fireEvent("datachanged", this);
5800 * Query the records by a specified property.
5801 * @param {String} field A field on your records
5802 * @param {String/RegExp} value Either a string that the field
5803 * should start with or a RegExp to test against the field
5804 * @param {Boolean} anyMatch True to match any part not just the beginning
5805 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5807 query : function(property, value, anyMatch){
5808 var fn = this.createFilterFn(property, value, anyMatch);
5809 return fn ? this.queryBy(fn) : this.data.clone();
5813 * Query by a function. The specified function will be called with each
5814 * record in this data source. If the function returns true the record is included
5816 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5817 * @param {Object} scope (optional) The scope of the function (defaults to this)
5818 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5820 queryBy : function(fn, scope){
5821 var data = this.snapshot || this.data;
5822 return data.filterBy(fn, scope||this);
5826 * Collects unique values for a particular dataIndex from this store.
5827 * @param {String} dataIndex The property to collect
5828 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5829 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5830 * @return {Array} An array of the unique values
5832 collect : function(dataIndex, allowNull, bypassFilter){
5833 var d = (bypassFilter === true && this.snapshot) ?
5834 this.snapshot.items : this.data.items;
5835 var v, sv, r = [], l = {};
5836 for(var i = 0, len = d.length; i < len; i++){
5837 v = d[i].data[dataIndex];
5839 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5848 * Revert to a view of the Record cache with no filtering applied.
5849 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5851 clearFilter : function(suppressEvent){
5852 if(this.snapshot && this.snapshot != this.data){
5853 this.data = this.snapshot;
5854 delete this.snapshot;
5855 if(suppressEvent !== true){
5856 this.fireEvent("datachanged", this);
5862 afterEdit : function(record){
5863 if(this.modified.indexOf(record) == -1){
5864 this.modified.push(record);
5866 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5870 afterReject : function(record){
5871 this.modified.remove(record);
5872 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5876 afterCommit : function(record){
5877 this.modified.remove(record);
5878 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5882 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5883 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5885 commitChanges : function(){
5886 var m = this.modified.slice(0);
5888 for(var i = 0, len = m.length; i < len; i++){
5894 * Cancel outstanding changes on all changed records.
5896 rejectChanges : function(){
5897 var m = this.modified.slice(0);
5899 for(var i = 0, len = m.length; i < len; i++){
5904 onMetaChange : function(meta, rtype, o){
5905 this.recordType = rtype;
5906 this.fields = rtype.prototype.fields;
5907 delete this.snapshot;
5908 this.sortInfo = meta.sortInfo || this.sortInfo;
5910 this.fireEvent('metachange', this, this.reader.meta);
5914 * Ext JS Library 1.1.1
5915 * Copyright(c) 2006-2007, Ext JS, LLC.
5917 * Originally Released Under LGPL - original licence link has changed is not relivant.
5920 * <script type="text/javascript">
5924 * @class Roo.data.SimpleStore
5925 * @extends Roo.data.Store
5926 * Small helper class to make creating Stores from Array data easier.
5927 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5928 * @cfg {Array} fields An array of field definition objects, or field name strings.
5929 * @cfg {Array} data The multi-dimensional array of data
5931 * @param {Object} config
5933 Roo.data.SimpleStore = function(config){
5934 Roo.data.SimpleStore.superclass.constructor.call(this, {
5936 reader: new Roo.data.ArrayReader({
5939 Roo.data.Record.create(config.fields)
5941 proxy : new Roo.data.MemoryProxy(config.data)
5945 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5947 * Ext JS Library 1.1.1
5948 * Copyright(c) 2006-2007, Ext JS, LLC.
5950 * Originally Released Under LGPL - original licence link has changed is not relivant.
5953 * <script type="text/javascript">
5958 * @extends Roo.data.Store
5959 * @class Roo.data.JsonStore
5960 * Small helper class to make creating Stores for JSON data easier. <br/>
5962 var store = new Roo.data.JsonStore({
5963 url: 'get-images.php',
5965 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5968 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5969 * JsonReader and HttpProxy (unless inline data is provided).</b>
5970 * @cfg {Array} fields An array of field definition objects, or field name strings.
5972 * @param {Object} config
5974 Roo.data.JsonStore = function(c){
5975 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5976 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5977 reader: new Roo.data.JsonReader(c, c.fields)
5980 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5982 * Ext JS Library 1.1.1
5983 * Copyright(c) 2006-2007, Ext JS, LLC.
5985 * Originally Released Under LGPL - original licence link has changed is not relivant.
5988 * <script type="text/javascript">
5992 Roo.data.Field = function(config){
5993 if(typeof config == "string"){
5994 config = {name: config};
5996 Roo.apply(this, config);
6002 var st = Roo.data.SortTypes;
6003 // named sortTypes are supported, here we look them up
6004 if(typeof this.sortType == "string"){
6005 this.sortType = st[this.sortType];
6008 // set default sortType for strings and dates
6012 this.sortType = st.asUCString;
6015 this.sortType = st.asDate;
6018 this.sortType = st.none;
6023 var stripRe = /[\$,%]/g;
6025 // prebuilt conversion function for this field, instead of
6026 // switching every time we're reading a value
6028 var cv, dateFormat = this.dateFormat;
6033 cv = function(v){ return v; };
6036 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
6040 return v !== undefined && v !== null && v !== '' ?
6041 parseInt(String(v).replace(stripRe, ""), 10) : '';
6046 return v !== undefined && v !== null && v !== '' ?
6047 parseFloat(String(v).replace(stripRe, ""), 10) : '';
6052 cv = function(v){ return v === true || v === "true" || v == 1; };
6059 if(v instanceof Date){
6063 if(dateFormat == "timestamp"){
6064 return new Date(v*1000);
6066 return Date.parseDate(v, dateFormat);
6068 var parsed = Date.parse(v);
6069 return parsed ? new Date(parsed) : null;
6078 Roo.data.Field.prototype = {
6086 * Ext JS Library 1.1.1
6087 * Copyright(c) 2006-2007, Ext JS, LLC.
6089 * Originally Released Under LGPL - original licence link has changed is not relivant.
6092 * <script type="text/javascript">
6095 // Base class for reading structured data from a data source. This class is intended to be
6096 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
6099 * @class Roo.data.DataReader
6100 * Base class for reading structured data from a data source. This class is intended to be
6101 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
6104 Roo.data.DataReader = function(meta, recordType){
6108 this.recordType = recordType instanceof Array ?
6109 Roo.data.Record.create(recordType) : recordType;
6112 Roo.data.DataReader.prototype = {
6114 * Create an empty record
6115 * @param {Object} data (optional) - overlay some values
6116 * @return {Roo.data.Record} record created.
6118 newRow : function(d) {
6120 this.recordType.prototype.fields.each(function(c) {
6122 case 'int' : da[c.name] = 0; break;
6123 case 'date' : da[c.name] = new Date(); break;
6124 case 'float' : da[c.name] = 0.0; break;
6125 case 'boolean' : da[c.name] = false; break;
6126 default : da[c.name] = ""; break;
6130 return new this.recordType(Roo.apply(da, d));
6135 * Ext JS Library 1.1.1
6136 * Copyright(c) 2006-2007, Ext JS, LLC.
6138 * Originally Released Under LGPL - original licence link has changed is not relivant.
6141 * <script type="text/javascript">
6145 * @class Roo.data.DataProxy
6146 * @extends Roo.data.Observable
6147 * This class is an abstract base class for implementations which provide retrieval of
6148 * unformatted data objects.<br>
6150 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
6151 * (of the appropriate type which knows how to parse the data object) to provide a block of
6152 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
6154 * Custom implementations must implement the load method as described in
6155 * {@link Roo.data.HttpProxy#load}.
6157 Roo.data.DataProxy = function(){
6161 * Fires before a network request is made to retrieve a data object.
6162 * @param {Object} This DataProxy object.
6163 * @param {Object} params The params parameter to the load function.
6168 * Fires before the load method's callback is called.
6169 * @param {Object} This DataProxy object.
6170 * @param {Object} o The data object.
6171 * @param {Object} arg The callback argument object passed to the load function.
6175 * @event loadexception
6176 * Fires if an Exception occurs during data retrieval.
6177 * @param {Object} This DataProxy object.
6178 * @param {Object} o The data object.
6179 * @param {Object} arg The callback argument object passed to the load function.
6180 * @param {Object} e The Exception.
6182 loadexception : true
6184 Roo.data.DataProxy.superclass.constructor.call(this);
6187 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
6190 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
6194 * Ext JS Library 1.1.1
6195 * Copyright(c) 2006-2007, Ext JS, LLC.
6197 * Originally Released Under LGPL - original licence link has changed is not relivant.
6200 * <script type="text/javascript">
6203 * @class Roo.data.MemoryProxy
6204 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
6205 * to the Reader when its load method is called.
6207 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
6209 Roo.data.MemoryProxy = function(data){
6213 Roo.data.MemoryProxy.superclass.constructor.call(this);
6217 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
6219 * Load data from the requested source (in this case an in-memory
6220 * data object passed to the constructor), read the data object into
6221 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6222 * process that block using the passed callback.
6223 * @param {Object} params This parameter is not used by the MemoryProxy class.
6224 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6225 * object into a block of Roo.data.Records.
6226 * @param {Function} callback The function into which to pass the block of Roo.data.records.
6227 * The function must be passed <ul>
6228 * <li>The Record block object</li>
6229 * <li>The "arg" argument from the load function</li>
6230 * <li>A boolean success indicator</li>
6232 * @param {Object} scope The scope in which to call the callback
6233 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6235 load : function(params, reader, callback, scope, arg){
6236 params = params || {};
6239 result = reader.readRecords(this.data);
6241 this.fireEvent("loadexception", this, arg, null, e);
6242 callback.call(scope, null, arg, false);
6245 callback.call(scope, result, arg, true);
6249 update : function(params, records){
6254 * Ext JS Library 1.1.1
6255 * Copyright(c) 2006-2007, Ext JS, LLC.
6257 * Originally Released Under LGPL - original licence link has changed is not relivant.
6260 * <script type="text/javascript">
6263 * @class Roo.data.HttpProxy
6264 * @extends Roo.data.DataProxy
6265 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
6266 * configured to reference a certain URL.<br><br>
6268 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
6269 * from which the running page was served.<br><br>
6271 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
6273 * Be aware that to enable the browser to parse an XML document, the server must set
6274 * the Content-Type header in the HTTP response to "text/xml".
6276 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
6277 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
6278 * will be used to make the request.
6280 Roo.data.HttpProxy = function(conn){
6281 Roo.data.HttpProxy.superclass.constructor.call(this);
6282 // is conn a conn config or a real conn?
6284 this.useAjax = !conn || !conn.events;
6288 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
6289 // thse are take from connection...
6292 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
6295 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
6296 * extra parameters to each request made by this object. (defaults to undefined)
6299 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
6300 * to each request made by this object. (defaults to undefined)
6303 * @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)
6306 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
6309 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
6315 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
6319 * Return the {@link Roo.data.Connection} object being used by this Proxy.
6320 * @return {Connection} The Connection object. This object may be used to subscribe to events on
6321 * a finer-grained basis than the DataProxy events.
6323 getConnection : function(){
6324 return this.useAjax ? Roo.Ajax : this.conn;
6328 * Load data from the configured {@link Roo.data.Connection}, read the data object into
6329 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
6330 * process that block using the passed callback.
6331 * @param {Object} params An object containing properties which are to be used as HTTP parameters
6332 * for the request to the remote server.
6333 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6334 * object into a block of Roo.data.Records.
6335 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6336 * The function must be passed <ul>
6337 * <li>The Record block object</li>
6338 * <li>The "arg" argument from the load function</li>
6339 * <li>A boolean success indicator</li>
6341 * @param {Object} scope The scope in which to call the callback
6342 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6344 load : function(params, reader, callback, scope, arg){
6345 if(this.fireEvent("beforeload", this, params) !== false){
6347 params : params || {},
6349 callback : callback,
6354 callback : this.loadResponse,
6358 Roo.applyIf(o, this.conn);
6359 if(this.activeRequest){
6360 Roo.Ajax.abort(this.activeRequest);
6362 this.activeRequest = Roo.Ajax.request(o);
6364 this.conn.request(o);
6367 callback.call(scope||this, null, arg, false);
6372 loadResponse : function(o, success, response){
6373 delete this.activeRequest;
6375 this.fireEvent("loadexception", this, o, response);
6376 o.request.callback.call(o.request.scope, null, o.request.arg, false);
6381 result = o.reader.read(response);
6383 this.fireEvent("loadexception", this, o, response, e);
6384 o.request.callback.call(o.request.scope, null, o.request.arg, false);
6388 this.fireEvent("load", this, o, o.request.arg);
6389 o.request.callback.call(o.request.scope, result, o.request.arg, true);
6393 update : function(dataSet){
6398 updateResponse : function(dataSet){
6403 * Ext JS Library 1.1.1
6404 * Copyright(c) 2006-2007, Ext JS, LLC.
6406 * Originally Released Under LGPL - original licence link has changed is not relivant.
6409 * <script type="text/javascript">
6413 * @class Roo.data.ScriptTagProxy
6414 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
6415 * other than the originating domain of the running page.<br><br>
6417 * <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
6418 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
6420 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
6421 * source code that is used as the source inside a <script> tag.<br><br>
6423 * In order for the browser to process the returned data, the server must wrap the data object
6424 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
6425 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
6426 * depending on whether the callback name was passed:
6429 boolean scriptTag = false;
6430 String cb = request.getParameter("callback");
6433 response.setContentType("text/javascript");
6435 response.setContentType("application/x-json");
6437 Writer out = response.getWriter();
6439 out.write(cb + "(");
6441 out.print(dataBlock.toJsonString());
6448 * @param {Object} config A configuration object.
6450 Roo.data.ScriptTagProxy = function(config){
6451 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
6452 Roo.apply(this, config);
6453 this.head = document.getElementsByTagName("head")[0];
6456 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
6458 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
6460 * @cfg {String} url The URL from which to request the data object.
6463 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
6467 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
6468 * the server the name of the callback function set up by the load call to process the returned data object.
6469 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
6470 * javascript output which calls this named function passing the data object as its only parameter.
6472 callbackParam : "callback",
6474 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
6475 * name to the request.
6480 * Load data from the configured URL, read the data object into
6481 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6482 * process that block using the passed callback.
6483 * @param {Object} params An object containing properties which are to be used as HTTP parameters
6484 * for the request to the remote server.
6485 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6486 * object into a block of Roo.data.Records.
6487 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6488 * The function must be passed <ul>
6489 * <li>The Record block object</li>
6490 * <li>The "arg" argument from the load function</li>
6491 * <li>A boolean success indicator</li>
6493 * @param {Object} scope The scope in which to call the callback
6494 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6496 load : function(params, reader, callback, scope, arg){
6497 if(this.fireEvent("beforeload", this, params) !== false){
6499 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
6502 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
6504 url += "&_dc=" + (new Date().getTime());
6506 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
6509 cb : "stcCallback"+transId,
6510 scriptId : "stcScript"+transId,
6514 callback : callback,
6520 window[trans.cb] = function(o){
6521 conn.handleResponse(o, trans);
6524 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
6526 if(this.autoAbort !== false){
6530 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
6532 var script = document.createElement("script");
6533 script.setAttribute("src", url);
6534 script.setAttribute("type", "text/javascript");
6535 script.setAttribute("id", trans.scriptId);
6536 this.head.appendChild(script);
6540 callback.call(scope||this, null, arg, false);
6545 isLoading : function(){
6546 return this.trans ? true : false;
6550 * Abort the current server request.
6553 if(this.isLoading()){
6554 this.destroyTrans(this.trans);
6559 destroyTrans : function(trans, isLoaded){
6560 this.head.removeChild(document.getElementById(trans.scriptId));
6561 clearTimeout(trans.timeoutId);
6563 window[trans.cb] = undefined;
6565 delete window[trans.cb];
6568 // if hasn't been loaded, wait for load to remove it to prevent script error
6569 window[trans.cb] = function(){
6570 window[trans.cb] = undefined;
6572 delete window[trans.cb];
6579 handleResponse : function(o, trans){
6581 this.destroyTrans(trans, true);
6584 result = trans.reader.readRecords(o);
6586 this.fireEvent("loadexception", this, o, trans.arg, e);
6587 trans.callback.call(trans.scope||window, null, trans.arg, false);
6590 this.fireEvent("load", this, o, trans.arg);
6591 trans.callback.call(trans.scope||window, result, trans.arg, true);
6595 handleFailure : function(trans){
6597 this.destroyTrans(trans, false);
6598 this.fireEvent("loadexception", this, null, trans.arg);
6599 trans.callback.call(trans.scope||window, null, trans.arg, false);
6603 * Ext JS Library 1.1.1
6604 * Copyright(c) 2006-2007, Ext JS, LLC.
6606 * Originally Released Under LGPL - original licence link has changed is not relivant.
6609 * <script type="text/javascript">
6613 * @class Roo.data.JsonReader
6614 * @extends Roo.data.DataReader
6615 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6616 * based on mappings in a provided Roo.data.Record constructor.
6618 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6619 * in the reply previously.
6624 var RecordDef = Roo.data.Record.create([
6625 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6626 {name: 'occupation'} // This field will use "occupation" as the mapping.
6628 var myReader = new Roo.data.JsonReader({
6629 totalProperty: "results", // The property which contains the total dataset size (optional)
6630 root: "rows", // The property which contains an Array of row objects
6631 id: "id" // The property within each row object that provides an ID for the record (optional)
6635 * This would consume a JSON file like this:
6637 { 'results': 2, 'rows': [
6638 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6639 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6642 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6643 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6644 * paged from the remote server.
6645 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6646 * @cfg {String} root name of the property which contains the Array of row objects.
6647 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6649 * Create a new JsonReader
6650 * @param {Object} meta Metadata configuration options
6651 * @param {Object} recordType Either an Array of field definition objects,
6652 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6654 Roo.data.JsonReader = function(meta, recordType){
6657 // set some defaults:
6659 totalProperty: 'total',
6660 successProperty : 'success',
6665 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6667 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6670 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6671 * Used by Store query builder to append _requestMeta to params.
6674 metaFromRemote : false,
6676 * This method is only used by a DataProxy which has retrieved data from a remote server.
6677 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6678 * @return {Object} data A data block which is used by an Roo.data.Store object as
6679 * a cache of Roo.data.Records.
6681 read : function(response){
6682 var json = response.responseText;
6684 var o = /* eval:var:o */ eval("("+json+")");
6686 throw {message: "JsonReader.read: Json object not found"};
6692 this.metaFromRemote = true;
6693 this.meta = o.metaData;
6694 this.recordType = Roo.data.Record.create(o.metaData.fields);
6695 this.onMetaChange(this.meta, this.recordType, o);
6697 return this.readRecords(o);
6700 // private function a store will implement
6701 onMetaChange : function(meta, recordType, o){
6708 simpleAccess: function(obj, subsc) {
6715 getJsonAccessor: function(){
6717 return function(expr) {
6719 return(re.test(expr))
6720 ? new Function("obj", "return obj." + expr)
6730 * Create a data block containing Roo.data.Records from an XML document.
6731 * @param {Object} o An object which contains an Array of row objects in the property specified
6732 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6733 * which contains the total size of the dataset.
6734 * @return {Object} data A data block which is used by an Roo.data.Store object as
6735 * a cache of Roo.data.Records.
6737 readRecords : function(o){
6739 * After any data loads, the raw JSON data is available for further custom processing.
6743 var s = this.meta, Record = this.recordType,
6744 f = Record.prototype.fields, fi = f.items, fl = f.length;
6746 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6748 if(s.totalProperty) {
6749 this.getTotal = this.getJsonAccessor(s.totalProperty);
6751 if(s.successProperty) {
6752 this.getSuccess = this.getJsonAccessor(s.successProperty);
6754 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6756 var g = this.getJsonAccessor(s.id);
6757 this.getId = function(rec) {
6759 return (r === undefined || r === "") ? null : r;
6762 this.getId = function(){return null;};
6765 for(var jj = 0; jj < fl; jj++){
6767 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6768 this.ef[jj] = this.getJsonAccessor(map);
6772 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6773 if(s.totalProperty){
6774 var vt = parseInt(this.getTotal(o), 10);
6779 if(s.successProperty){
6780 var vs = this.getSuccess(o);
6781 if(vs === false || vs === 'false'){
6786 for(var i = 0; i < c; i++){
6789 var id = this.getId(n);
6790 for(var j = 0; j < fl; j++){
6792 var v = this.ef[j](n);
6794 Roo.log('missing convert for ' + f.name);
6798 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6800 var record = new Record(values, id);
6802 records[i] = record;
6808 totalRecords : totalRecords
6813 * Ext JS Library 1.1.1
6814 * Copyright(c) 2006-2007, Ext JS, LLC.
6816 * Originally Released Under LGPL - original licence link has changed is not relivant.
6819 * <script type="text/javascript">
6823 * @class Roo.data.ArrayReader
6824 * @extends Roo.data.DataReader
6825 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6826 * Each element of that Array represents a row of data fields. The
6827 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6828 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6832 var RecordDef = Roo.data.Record.create([
6833 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6834 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6836 var myReader = new Roo.data.ArrayReader({
6837 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6841 * This would consume an Array like this:
6843 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6845 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6847 * Create a new JsonReader
6848 * @param {Object} meta Metadata configuration options.
6849 * @param {Object} recordType Either an Array of field definition objects
6850 * as specified to {@link Roo.data.Record#create},
6851 * or an {@link Roo.data.Record} object
6852 * created using {@link Roo.data.Record#create}.
6854 Roo.data.ArrayReader = function(meta, recordType){
6855 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6858 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6860 * Create a data block containing Roo.data.Records from an XML document.
6861 * @param {Object} o An Array of row objects which represents the dataset.
6862 * @return {Object} data A data block which is used by an Roo.data.Store object as
6863 * a cache of Roo.data.Records.
6865 readRecords : function(o){
6866 var sid = this.meta ? this.meta.id : null;
6867 var recordType = this.recordType, fields = recordType.prototype.fields;
6870 for(var i = 0; i < root.length; i++){
6873 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6874 for(var j = 0, jlen = fields.length; j < jlen; j++){
6875 var f = fields.items[j];
6876 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6877 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6881 var record = new recordType(values, id);
6883 records[records.length] = record;
6887 totalRecords : records.length
6896 * @class Roo.bootstrap.ComboBox
6897 * @extends Roo.bootstrap.TriggerField
6898 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
6900 * Create a new ComboBox.
6901 * @param {Object} config Configuration options
6903 Roo.bootstrap.ComboBox = function(config){
6904 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
6908 * Fires when the dropdown list is expanded
6909 * @param {Roo.bootstrap.ComboBox} combo This combo box
6914 * Fires when the dropdown list is collapsed
6915 * @param {Roo.bootstrap.ComboBox} combo This combo box
6919 * @event beforeselect
6920 * Fires before a list item is selected. Return false to cancel the selection.
6921 * @param {Roo.bootstrap.ComboBox} combo This combo box
6922 * @param {Roo.data.Record} record The data record returned from the underlying store
6923 * @param {Number} index The index of the selected item in the dropdown list
6925 'beforeselect' : true,
6928 * Fires when a list item is selected
6929 * @param {Roo.bootstrap.ComboBox} combo This combo box
6930 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
6931 * @param {Number} index The index of the selected item in the dropdown list
6935 * @event beforequery
6936 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
6937 * The event object passed has these properties:
6938 * @param {Roo.bootstrap.ComboBox} combo This combo box
6939 * @param {String} query The query
6940 * @param {Boolean} forceAll true to force "all" query
6941 * @param {Boolean} cancel true to cancel the query
6942 * @param {Object} e The query event object
6944 'beforequery': true,
6947 * Fires when the 'add' icon is pressed (add a listener to enable add button)
6948 * @param {Roo.bootstrap.ComboBox} combo This combo box
6953 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
6954 * @param {Roo.bootstrap.ComboBox} combo This combo box
6955 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
6963 this.selectedIndex = -1;
6964 if(this.mode == 'local'){
6965 if(config.queryDelay === undefined){
6966 this.queryDelay = 10;
6968 if(config.minChars === undefined){
6974 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
6977 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
6978 * rendering into an Roo.Editor, defaults to false)
6981 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
6982 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
6985 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
6988 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
6989 * the dropdown list (defaults to undefined, with no header element)
6993 * @cfg {String/Roo.Template} tpl The template to use to render the output
6997 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
6999 listWidth: undefined,
7001 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
7002 * mode = 'remote' or 'text' if mode = 'local')
7004 displayField: undefined,
7006 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
7007 * mode = 'remote' or 'value' if mode = 'local').
7008 * Note: use of a valueField requires the user make a selection
7009 * in order for a value to be mapped.
7011 valueField: undefined,
7015 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
7016 * field's data value (defaults to the underlying DOM element's name)
7018 hiddenName: undefined,
7020 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
7024 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
7026 selectedClass: 'active',
7029 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
7033 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
7034 * anchor positions (defaults to 'tl-bl')
7036 listAlign: 'tl-bl?',
7038 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
7042 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
7043 * query specified by the allQuery config option (defaults to 'query')
7045 triggerAction: 'query',
7047 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
7048 * (defaults to 4, does not apply if editable = false)
7052 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
7053 * delay (typeAheadDelay) if it matches a known value (defaults to false)
7057 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
7058 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
7062 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
7063 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
7067 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
7068 * when editable = true (defaults to false)
7070 selectOnFocus:false,
7072 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
7074 queryParam: 'query',
7076 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
7077 * when mode = 'remote' (defaults to 'Loading...')
7079 loadingText: 'Loading...',
7081 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
7085 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
7089 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
7090 * traditional select (defaults to true)
7094 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
7098 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
7102 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
7103 * listWidth has a higher value)
7107 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
7108 * allow the user to set arbitrary text into the field (defaults to false)
7110 forceSelection:false,
7112 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
7113 * if typeAhead = true (defaults to 250)
7115 typeAheadDelay : 250,
7117 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
7118 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
7120 valueNotFoundText : undefined,
7122 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
7127 * @cfg {Boolean} disableClear Disable showing of clear button.
7129 disableClear : false,
7131 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
7133 alwaysQuery : false,
7139 // element that contains real text value.. (when hidden is used..)
7142 initEvents: function(){
7145 throw "can not find store for combo";
7147 this.store = Roo.factory(this.store, Roo.data);
7151 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
7154 if(this.hiddenName){
7156 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
7158 this.hiddenField.dom.value =
7159 this.hiddenValue !== undefined ? this.hiddenValue :
7160 this.value !== undefined ? this.value : '';
7162 // prevent input submission
7163 this.el.dom.removeAttribute('name');
7164 this.hiddenField.dom.setAttribute('name', this.hiddenName);
7169 // this.el.dom.setAttribute('autocomplete', 'off');
7172 var cls = 'x-combo-list';
7173 this.list = this.el.select('ul',true).first();
7175 //this.list = new Roo.Layer({
7176 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
7179 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
7180 this.list.setWidth(lw);
7182 this.list.on('mouseover', this.onViewOver, this);
7183 this.list.on('mousemove', this.onViewMove, this);
7186 this.list.swallowEvent('mousewheel');
7187 this.assetHeight = 0;
7190 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
7191 this.assetHeight += this.header.getHeight();
7194 this.innerList = this.list.createChild({cls:cls+'-inner'});
7195 this.innerList.on('mouseover', this.onViewOver, this);
7196 this.innerList.on('mousemove', this.onViewMove, this);
7197 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7199 if(this.allowBlank && !this.pageSize && !this.disableClear){
7200 this.footer = this.list.createChild({cls:cls+'-ft'});
7201 this.pageTb = new Roo.Toolbar(this.footer);
7205 this.footer = this.list.createChild({cls:cls+'-ft'});
7206 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
7207 {pageSize: this.pageSize});
7211 if (this.pageTb && this.allowBlank && !this.disableClear) {
7213 this.pageTb.add(new Roo.Toolbar.Fill(), {
7214 cls: 'x-btn-icon x-btn-clear',
7220 _this.onSelect(false, -1);
7225 this.assetHeight += this.footer.getHeight();
7230 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
7233 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
7234 singleSelect:true, store: this.store, selectedClass: this.selectedClass
7236 //this.view.wrapEl.setDisplayed(false);
7237 this.view.on('click', this.onViewClick, this);
7241 this.store.on('beforeload', this.onBeforeLoad, this);
7242 this.store.on('load', this.onLoad, this);
7243 this.store.on('loadexception', this.onLoadException, this);
7246 this.resizer = new Roo.Resizable(this.list, {
7247 pinned:true, handles:'se'
7249 this.resizer.on('resize', function(r, w, h){
7250 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
7252 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
7253 this.restrictHeight();
7255 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
7259 this.editable = true;
7260 this.setEditable(false);
7265 if (typeof(this.events.add.listeners) != 'undefined') {
7267 this.addicon = this.wrap.createChild(
7268 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
7270 this.addicon.on('click', function(e) {
7271 this.fireEvent('add', this);
7274 if (typeof(this.events.edit.listeners) != 'undefined') {
7276 this.editicon = this.wrap.createChild(
7277 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
7279 this.editicon.setStyle('margin-left', '40px');
7281 this.editicon.on('click', function(e) {
7283 // we fire even if inothing is selected..
7284 this.fireEvent('edit', this, this.lastData );
7291 this.keyNav = new Roo.KeyNav(this.inputEl(), {
7293 this.inKeyMode = true;
7297 "down" : function(e){
7298 if(!this.isExpanded()){
7299 this.onTriggerClick();
7301 this.inKeyMode = true;
7306 "enter" : function(e){
7311 "esc" : function(e){
7315 "tab" : function(e){
7316 this.onViewClick(false);
7317 this.fireEvent("specialkey", this, e);
7323 doRelay : function(foo, bar, hname){
7324 if(hname == 'down' || this.scope.isExpanded()){
7325 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
7334 this.queryDelay = Math.max(this.queryDelay || 10,
7335 this.mode == 'local' ? 10 : 250);
7338 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
7341 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
7343 if(this.editable !== false){
7344 this.inputEl().on("keyup", this.onKeyUp, this);
7346 if(this.forceSelection){
7347 this.on('blur', this.doForce, this);
7351 onDestroy : function(){
7353 this.view.setStore(null);
7354 this.view.el.removeAllListeners();
7355 this.view.el.remove();
7356 this.view.purgeListeners();
7359 this.list.dom.innerHTML = '';
7362 this.store.un('beforeload', this.onBeforeLoad, this);
7363 this.store.un('load', this.onLoad, this);
7364 this.store.un('loadexception', this.onLoadException, this);
7366 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
7370 fireKey : function(e){
7371 if(e.isNavKeyPress() && !this.list.isVisible()){
7372 this.fireEvent("specialkey", this, e);
7377 onResize: function(w, h){
7378 Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
7380 if(typeof w != 'number'){
7381 // we do not handle it!?!?
7384 var tw = this.trigger.getWidth();
7385 // tw += this.addicon ? this.addicon.getWidth() : 0;
7386 // tw += this.editicon ? this.editicon.getWidth() : 0;
7388 this.inputEl().setWidth( this.adjustWidth('input', x));
7390 //this.trigger.setStyle('left', x+'px');
7392 if(this.list && this.listWidth === undefined){
7393 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
7394 this.list.setWidth(lw);
7395 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7403 * Allow or prevent the user from directly editing the field text. If false is passed,
7404 * the user will only be able to select from the items defined in the dropdown list. This method
7405 * is the runtime equivalent of setting the 'editable' config option at config time.
7406 * @param {Boolean} value True to allow the user to directly edit the field text
7408 setEditable : function(value){
7409 if(value == this.editable){
7412 this.editable = value;
7414 this.inputEl().dom.setAttribute('readOnly', true);
7415 this.inputEl().on('mousedown', this.onTriggerClick, this);
7416 this.inputEl().addClass('x-combo-noedit');
7418 this.inputEl().dom.setAttribute('readOnly', false);
7419 this.inputEl().un('mousedown', this.onTriggerClick, this);
7420 this.inputEl().removeClass('x-combo-noedit');
7425 onBeforeLoad : function(){
7429 //this.innerList.update(this.loadingText ?
7430 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
7431 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
7433 this.restrictHeight();
7434 this.selectedIndex = -1;
7438 onLoad : function(){
7442 if(this.store.getCount() > 0){
7444 this.restrictHeight();
7445 if(this.lastQuery == this.allQuery){
7447 this.inputEl().dom.select();
7449 if(!this.selectByValue(this.value, true)){
7450 this.select(0, true);
7454 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
7455 this.taTask.delay(this.typeAheadDelay);
7459 this.onEmptyResults();
7464 onLoadException : function()
7467 Roo.log(this.store.reader.jsonData);
7468 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7470 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7476 onTypeAhead : function(){
7477 if(this.store.getCount() > 0){
7478 var r = this.store.getAt(0);
7479 var newValue = r.data[this.displayField];
7480 var len = newValue.length;
7481 var selStart = this.getRawValue().length;
7483 if(selStart != len){
7484 this.setRawValue(newValue);
7485 this.selectText(selStart, newValue.length);
7491 onSelect : function(record, index){
7492 if(this.fireEvent('beforeselect', this, record, index) !== false){
7493 this.setFromData(index > -1 ? record.data : false);
7495 this.fireEvent('select', this, record, index);
7500 * Returns the currently selected field value or empty string if no value is set.
7501 * @return {String} value The selected value
7503 getValue : function(){
7504 if(this.valueField){
7505 return typeof this.value != 'undefined' ? this.value : '';
7507 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
7512 * Clears any text/value currently set in the field
7514 clearValue : function(){
7515 if(this.hiddenField){
7516 this.hiddenField.dom.value = '';
7519 this.setRawValue('');
7520 this.lastSelectionText = '';
7525 * Sets the specified value into the field. If the value finds a match, the corresponding record text
7526 * will be displayed in the field. If the value does not match the data value of an existing item,
7527 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
7528 * Otherwise the field will be blank (although the value will still be set).
7529 * @param {String} value The value to match
7531 setValue : function(v){
7533 if(this.valueField){
7534 var r = this.findRecord(this.valueField, v);
7536 text = r.data[this.displayField];
7537 }else if(this.valueNotFoundText !== undefined){
7538 text = this.valueNotFoundText;
7541 this.lastSelectionText = text;
7542 if(this.hiddenField){
7543 this.hiddenField.dom.value = v;
7545 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
7549 * @property {Object} the last set data for the element
7554 * Sets the value of the field based on a object which is related to the record format for the store.
7555 * @param {Object} value the value to set as. or false on reset?
7557 setFromData : function(o){
7558 var dv = ''; // display value
7559 var vv = ''; // value value..
7561 if (this.displayField) {
7562 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
7564 // this is an error condition!!!
7565 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
7568 if(this.valueField){
7569 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
7571 if(this.hiddenField){
7572 this.hiddenField.dom.value = vv;
7574 this.lastSelectionText = dv;
7575 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7579 // no hidden field.. - we store the value in 'value', but still display
7580 // display field!!!!
7581 this.lastSelectionText = dv;
7582 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7589 // overridden so that last data is reset..
7590 this.setValue(this.originalValue);
7591 this.clearInvalid();
7592 this.lastData = false;
7594 this.view.clearSelections();
7598 findRecord : function(prop, value){
7600 if(this.store.getCount() > 0){
7601 this.store.each(function(r){
7602 if(r.data[prop] == value){
7614 // returns hidden if it's set..
7615 if (!this.rendered) {return ''};
7616 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
7620 onViewMove : function(e, t){
7621 this.inKeyMode = false;
7625 onViewOver : function(e, t){
7626 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
7629 var item = this.view.findItemFromChild(t);
7631 var index = this.view.indexOf(item);
7632 this.select(index, false);
7637 onViewClick : function(doFocus)
7639 var index = this.view.getSelectedIndexes()[0];
7640 var r = this.store.getAt(index);
7642 this.onSelect(r, index);
7644 if(doFocus !== false && !this.blockFocus){
7645 this.inputEl().focus();
7650 restrictHeight : function(){
7651 //this.innerList.dom.style.height = '';
7652 //var inner = this.innerList.dom;
7653 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
7654 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
7655 //this.list.beginUpdate();
7656 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
7657 this.list.alignTo(this.inputEl(), this.listAlign);
7658 //this.list.endUpdate();
7662 onEmptyResults : function(){
7667 * Returns true if the dropdown list is expanded, else false.
7669 isExpanded : function(){
7670 return this.list.isVisible();
7674 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
7675 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7676 * @param {String} value The data value of the item to select
7677 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7678 * selected item if it is not currently in view (defaults to true)
7679 * @return {Boolean} True if the value matched an item in the list, else false
7681 selectByValue : function(v, scrollIntoView){
7682 if(v !== undefined && v !== null){
7683 var r = this.findRecord(this.valueField || this.displayField, v);
7685 this.select(this.store.indexOf(r), scrollIntoView);
7693 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
7694 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7695 * @param {Number} index The zero-based index of the list item to select
7696 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7697 * selected item if it is not currently in view (defaults to true)
7699 select : function(index, scrollIntoView){
7700 this.selectedIndex = index;
7701 this.view.select(index);
7702 if(scrollIntoView !== false){
7703 var el = this.view.getNode(index);
7705 //this.innerList.scrollChildIntoView(el, false);
7712 selectNext : function(){
7713 var ct = this.store.getCount();
7715 if(this.selectedIndex == -1){
7717 }else if(this.selectedIndex < ct-1){
7718 this.select(this.selectedIndex+1);
7724 selectPrev : function(){
7725 var ct = this.store.getCount();
7727 if(this.selectedIndex == -1){
7729 }else if(this.selectedIndex != 0){
7730 this.select(this.selectedIndex-1);
7736 onKeyUp : function(e){
7737 if(this.editable !== false && !e.isSpecialKey()){
7738 this.lastKey = e.getKey();
7739 this.dqTask.delay(this.queryDelay);
7744 validateBlur : function(){
7745 return !this.list || !this.list.isVisible();
7749 initQuery : function(){
7750 this.doQuery(this.getRawValue());
7754 doForce : function(){
7755 if(this.el.dom.value.length > 0){
7757 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
7763 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
7764 * query allowing the query action to be canceled if needed.
7765 * @param {String} query The SQL query to execute
7766 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
7767 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
7768 * saved in the current store (defaults to false)
7770 doQuery : function(q, forceAll){
7771 if(q === undefined || q === null){
7780 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
7784 forceAll = qe.forceAll;
7785 if(forceAll === true || (q.length >= this.minChars)){
7786 if(this.lastQuery != q || this.alwaysQuery){
7788 if(this.mode == 'local'){
7789 this.selectedIndex = -1;
7791 this.store.clearFilter();
7793 this.store.filter(this.displayField, q);
7797 this.store.baseParams[this.queryParam] = q;
7799 params: this.getParams(q)
7804 this.selectedIndex = -1;
7811 getParams : function(q){
7813 //p[this.queryParam] = q;
7816 p.limit = this.pageSize;
7822 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
7824 collapse : function(){
7825 if(!this.isExpanded()){
7829 Roo.get(document).un('mousedown', this.collapseIf, this);
7830 Roo.get(document).un('mousewheel', this.collapseIf, this);
7831 if (!this.editable) {
7832 Roo.get(document).un('keydown', this.listKeyPress, this);
7834 this.fireEvent('collapse', this);
7838 collapseIf : function(e){
7839 if(!e.within(this.el) && !e.within(this.el)){
7845 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
7847 expand : function(){
7849 if(this.isExpanded() || !this.hasFocus){
7852 this.list.alignTo(this.inputEl(), this.listAlign);
7854 Roo.get(document).on('mousedown', this.collapseIf, this);
7855 Roo.get(document).on('mousewheel', this.collapseIf, this);
7856 if (!this.editable) {
7857 Roo.get(document).on('keydown', this.listKeyPress, this);
7860 this.fireEvent('expand', this);
7864 // Implements the default empty TriggerField.onTriggerClick function
7865 onTriggerClick : function()
7867 Roo.log('trigger click');
7872 if(this.isExpanded()){
7874 if (!this.blockFocus) {
7875 this.inputEl().focus();
7879 this.hasFocus = true;
7880 if(this.triggerAction == 'all') {
7881 this.doQuery(this.allQuery, true);
7883 this.doQuery(this.getRawValue());
7885 if (!this.blockFocus) {
7886 this.inputEl().focus();
7890 listKeyPress : function(e)
7892 //Roo.log('listkeypress');
7893 // scroll to first matching element based on key pres..
7894 if (e.isSpecialKey()) {
7897 var k = String.fromCharCode(e.getKey()).toUpperCase();
7900 var csel = this.view.getSelectedNodes();
7901 var cselitem = false;
7903 var ix = this.view.indexOf(csel[0]);
7904 cselitem = this.store.getAt(ix);
7905 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
7911 this.store.each(function(v) {
7913 // start at existing selection.
7914 if (cselitem.id == v.id) {
7920 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
7921 match = this.store.indexOf(v);
7927 if (match === false) {
7928 return true; // no more action?
7931 this.view.select(match);
7932 var sn = Roo.get(this.view.getSelectedNodes()[0])
7933 //sn.scrollIntoView(sn.dom.parentNode, false);
7937 * @cfg {Boolean} grow
7941 * @cfg {Number} growMin
7945 * @cfg {Number} growMax
7954 * Ext JS Library 1.1.1
7955 * Copyright(c) 2006-2007, Ext JS, LLC.
7957 * Originally Released Under LGPL - original licence link has changed is not relivant.
7960 * <script type="text/javascript">
7965 * @extends Roo.util.Observable
7966 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
7967 * This class also supports single and multi selection modes. <br>
7968 * Create a data model bound view:
7970 var store = new Roo.data.Store(...);
7972 var view = new Roo.View({
7974 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
7977 selectedClass: "ydataview-selected",
7981 // listen for node click?
7982 view.on("click", function(vw, index, node, e){
7983 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
7987 dataModel.load("foobar.xml");
7989 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
7991 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
7992 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
7994 * Note: old style constructor is still suported (container, template, config)
7998 * @param {Object} config The config object
8001 Roo.View = function(config, depreciated_tpl, depreciated_config){
8003 if (typeof(depreciated_tpl) == 'undefined') {
8004 // new way.. - universal constructor.
8005 Roo.apply(this, config);
8006 this.el = Roo.get(this.el);
8009 this.el = Roo.get(config);
8010 this.tpl = depreciated_tpl;
8011 Roo.apply(this, depreciated_config);
8013 this.wrapEl = this.el.wrap().wrap();
8014 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
8017 if(typeof(this.tpl) == "string"){
8018 this.tpl = new Roo.Template(this.tpl);
8020 // support xtype ctors..
8021 this.tpl = new Roo.factory(this.tpl, Roo);
8033 * @event beforeclick
8034 * Fires before a click is processed. Returns false to cancel the default action.
8035 * @param {Roo.View} this
8036 * @param {Number} index The index of the target node
8037 * @param {HTMLElement} node The target node
8038 * @param {Roo.EventObject} e The raw event object
8040 "beforeclick" : true,
8043 * Fires when a template node is clicked.
8044 * @param {Roo.View} this
8045 * @param {Number} index The index of the target node
8046 * @param {HTMLElement} node The target node
8047 * @param {Roo.EventObject} e The raw event object
8052 * Fires when a template node is double clicked.
8053 * @param {Roo.View} this
8054 * @param {Number} index The index of the target node
8055 * @param {HTMLElement} node The target node
8056 * @param {Roo.EventObject} e The raw event object
8060 * @event contextmenu
8061 * Fires when a template node is right clicked.
8062 * @param {Roo.View} this
8063 * @param {Number} index The index of the target node
8064 * @param {HTMLElement} node The target node
8065 * @param {Roo.EventObject} e The raw event object
8067 "contextmenu" : true,
8069 * @event selectionchange
8070 * Fires when the selected nodes change.
8071 * @param {Roo.View} this
8072 * @param {Array} selections Array of the selected nodes
8074 "selectionchange" : true,
8077 * @event beforeselect
8078 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
8079 * @param {Roo.View} this
8080 * @param {HTMLElement} node The node to be selected
8081 * @param {Array} selections Array of currently selected nodes
8083 "beforeselect" : true,
8085 * @event preparedata
8086 * Fires on every row to render, to allow you to change the data.
8087 * @param {Roo.View} this
8088 * @param {Object} data to be rendered (change this)
8090 "preparedata" : true
8098 "click": this.onClick,
8099 "dblclick": this.onDblClick,
8100 "contextmenu": this.onContextMenu,
8104 this.selections = [];
8106 this.cmp = new Roo.CompositeElementLite([]);
8108 this.store = Roo.factory(this.store, Roo.data);
8109 this.setStore(this.store, true);
8112 if ( this.footer && this.footer.xtype) {
8114 var fctr = this.wrapEl.appendChild(document.createElement("div"));
8116 this.footer.dataSource = this.store
8117 this.footer.container = fctr;
8118 this.footer = Roo.factory(this.footer, Roo);
8119 fctr.insertFirst(this.el);
8121 // this is a bit insane - as the paging toolbar seems to detach the el..
8122 // dom.parentNode.parentNode.parentNode
8123 // they get detached?
8127 Roo.View.superclass.constructor.call(this);
8132 Roo.extend(Roo.View, Roo.util.Observable, {
8135 * @cfg {Roo.data.Store} store Data store to load data from.
8140 * @cfg {String|Roo.Element} el The container element.
8145 * @cfg {String|Roo.Template} tpl The template used by this View
8149 * @cfg {String} dataName the named area of the template to use as the data area
8150 * Works with domtemplates roo-name="name"
8154 * @cfg {String} selectedClass The css class to add to selected nodes
8156 selectedClass : "x-view-selected",
8158 * @cfg {String} emptyText The empty text to show when nothing is loaded.
8163 * @cfg {String} text to display on mask (default Loading)
8167 * @cfg {Boolean} multiSelect Allow multiple selection
8169 multiSelect : false,
8171 * @cfg {Boolean} singleSelect Allow single selection
8173 singleSelect: false,
8176 * @cfg {Boolean} toggleSelect - selecting
8178 toggleSelect : false,
8181 * Returns the element this view is bound to.
8182 * @return {Roo.Element}
8191 * Refreshes the view. - called by datachanged on the store. - do not call directly.
8193 refresh : function(){
8196 // if we are using something like 'domtemplate', then
8197 // the what gets used is:
8198 // t.applySubtemplate(NAME, data, wrapping data..)
8199 // the outer template then get' applied with
8200 // the store 'extra data'
8201 // and the body get's added to the
8202 // roo-name="data" node?
8203 // <span class='roo-tpl-{name}'></span> ?????
8207 this.clearSelections();
8210 var records = this.store.getRange();
8211 if(records.length < 1) {
8213 // is this valid?? = should it render a template??
8215 this.el.update(this.emptyText);
8219 if (this.dataName) {
8220 this.el.update(t.apply(this.store.meta)); //????
8221 el = this.el.child('.roo-tpl-' + this.dataName);
8224 for(var i = 0, len = records.length; i < len; i++){
8225 var data = this.prepareData(records[i].data, i, records[i]);
8226 this.fireEvent("preparedata", this, data, i, records[i]);
8227 html[html.length] = Roo.util.Format.trim(
8229 t.applySubtemplate(this.dataName, data, this.store.meta) :
8236 el.update(html.join(""));
8237 this.nodes = el.dom.childNodes;
8238 this.updateIndexes(0);
8242 * Function to override to reformat the data that is sent to
8243 * the template for each node.
8244 * DEPRICATED - use the preparedata event handler.
8245 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
8246 * a JSON object for an UpdateManager bound view).
8248 prepareData : function(data, index, record)
8250 this.fireEvent("preparedata", this, data, index, record);
8254 onUpdate : function(ds, record){
8255 this.clearSelections();
8256 var index = this.store.indexOf(record);
8257 var n = this.nodes[index];
8258 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
8259 n.parentNode.removeChild(n);
8260 this.updateIndexes(index, index);
8266 onAdd : function(ds, records, index)
8268 this.clearSelections();
8269 if(this.nodes.length == 0){
8273 var n = this.nodes[index];
8274 for(var i = 0, len = records.length; i < len; i++){
8275 var d = this.prepareData(records[i].data, i, records[i]);
8277 this.tpl.insertBefore(n, d);
8280 this.tpl.append(this.el, d);
8283 this.updateIndexes(index);
8286 onRemove : function(ds, record, index){
8287 this.clearSelections();
8288 var el = this.dataName ?
8289 this.el.child('.roo-tpl-' + this.dataName) :
8291 el.dom.removeChild(this.nodes[index]);
8292 this.updateIndexes(index);
8296 * Refresh an individual node.
8297 * @param {Number} index
8299 refreshNode : function(index){
8300 this.onUpdate(this.store, this.store.getAt(index));
8303 updateIndexes : function(startIndex, endIndex){
8304 var ns = this.nodes;
8305 startIndex = startIndex || 0;
8306 endIndex = endIndex || ns.length - 1;
8307 for(var i = startIndex; i <= endIndex; i++){
8308 ns[i].nodeIndex = i;
8313 * Changes the data store this view uses and refresh the view.
8314 * @param {Store} store
8316 setStore : function(store, initial){
8317 if(!initial && this.store){
8318 this.store.un("datachanged", this.refresh);
8319 this.store.un("add", this.onAdd);
8320 this.store.un("remove", this.onRemove);
8321 this.store.un("update", this.onUpdate);
8322 this.store.un("clear", this.refresh);
8323 this.store.un("beforeload", this.onBeforeLoad);
8324 this.store.un("load", this.onLoad);
8325 this.store.un("loadexception", this.onLoad);
8329 store.on("datachanged", this.refresh, this);
8330 store.on("add", this.onAdd, this);
8331 store.on("remove", this.onRemove, this);
8332 store.on("update", this.onUpdate, this);
8333 store.on("clear", this.refresh, this);
8334 store.on("beforeload", this.onBeforeLoad, this);
8335 store.on("load", this.onLoad, this);
8336 store.on("loadexception", this.onLoad, this);
8344 * onbeforeLoad - masks the loading area.
8347 onBeforeLoad : function()
8350 this.el.mask(this.mask ? this.mask : "Loading" );
8352 onLoad : function ()
8359 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
8360 * @param {HTMLElement} node
8361 * @return {HTMLElement} The template node
8363 findItemFromChild : function(node){
8364 var el = this.dataName ?
8365 this.el.child('.roo-tpl-' + this.dataName,true) :
8368 if(!node || node.parentNode == el){
8371 var p = node.parentNode;
8372 while(p && p != el){
8373 if(p.parentNode == el){
8382 onClick : function(e){
8383 var item = this.findItemFromChild(e.getTarget());
8385 var index = this.indexOf(item);
8386 if(this.onItemClick(item, index, e) !== false){
8387 this.fireEvent("click", this, index, item, e);
8390 this.clearSelections();
8395 onContextMenu : function(e){
8396 var item = this.findItemFromChild(e.getTarget());
8398 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
8403 onDblClick : function(e){
8404 var item = this.findItemFromChild(e.getTarget());
8406 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
8410 onItemClick : function(item, index, e)
8412 if(this.fireEvent("beforeclick", this, index, item, e) === false){
8415 if (this.toggleSelect) {
8416 var m = this.isSelected(item) ? 'unselect' : 'select';
8419 _t[m](item, true, false);
8422 if(this.multiSelect || this.singleSelect){
8423 if(this.multiSelect && e.shiftKey && this.lastSelection){
8424 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
8426 this.select(item, this.multiSelect && e.ctrlKey);
8427 this.lastSelection = item;
8435 * Get the number of selected nodes.
8438 getSelectionCount : function(){
8439 return this.selections.length;
8443 * Get the currently selected nodes.
8444 * @return {Array} An array of HTMLElements
8446 getSelectedNodes : function(){
8447 return this.selections;
8451 * Get the indexes of the selected nodes.
8454 getSelectedIndexes : function(){
8455 var indexes = [], s = this.selections;
8456 for(var i = 0, len = s.length; i < len; i++){
8457 indexes.push(s[i].nodeIndex);
8463 * Clear all selections
8464 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
8466 clearSelections : function(suppressEvent){
8467 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
8468 this.cmp.elements = this.selections;
8469 this.cmp.removeClass(this.selectedClass);
8470 this.selections = [];
8472 this.fireEvent("selectionchange", this, this.selections);
8478 * Returns true if the passed node is selected
8479 * @param {HTMLElement/Number} node The node or node index
8482 isSelected : function(node){
8483 var s = this.selections;
8487 node = this.getNode(node);
8488 return s.indexOf(node) !== -1;
8493 * @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
8494 * @param {Boolean} keepExisting (optional) true to keep existing selections
8495 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8497 select : function(nodeInfo, keepExisting, suppressEvent){
8498 if(nodeInfo instanceof Array){
8500 this.clearSelections(true);
8502 for(var i = 0, len = nodeInfo.length; i < len; i++){
8503 this.select(nodeInfo[i], true, true);
8507 var node = this.getNode(nodeInfo);
8508 if(!node || this.isSelected(node)){
8509 return; // already selected.
8512 this.clearSelections(true);
8514 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
8515 Roo.fly(node).addClass(this.selectedClass);
8516 this.selections.push(node);
8518 this.fireEvent("selectionchange", this, this.selections);
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 IGNORED (for campatibility with select)
8528 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8530 unselect : function(nodeInfo, keepExisting, suppressEvent)
8532 if(nodeInfo instanceof Array){
8533 Roo.each(this.selections, function(s) {
8534 this.unselect(s, nodeInfo);
8538 var node = this.getNode(nodeInfo);
8539 if(!node || !this.isSelected(node)){
8540 Roo.log("not selected");
8541 return; // not selected.
8545 Roo.each(this.selections, function(s) {
8547 Roo.fly(node).removeClass(this.selectedClass);
8554 this.selections= ns;
8555 this.fireEvent("selectionchange", this, this.selections);
8559 * Gets a template node.
8560 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8561 * @return {HTMLElement} The node or null if it wasn't found
8563 getNode : function(nodeInfo){
8564 if(typeof nodeInfo == "string"){
8565 return document.getElementById(nodeInfo);
8566 }else if(typeof nodeInfo == "number"){
8567 return this.nodes[nodeInfo];
8573 * Gets a range template nodes.
8574 * @param {Number} startIndex
8575 * @param {Number} endIndex
8576 * @return {Array} An array of nodes
8578 getNodes : function(start, end){
8579 var ns = this.nodes;
8581 end = typeof end == "undefined" ? ns.length - 1 : end;
8584 for(var i = start; i <= end; i++){
8588 for(var i = start; i >= end; i--){
8596 * Finds the index of the passed node
8597 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8598 * @return {Number} The index of the node or -1
8600 indexOf : function(node){
8601 node = this.getNode(node);
8602 if(typeof node.nodeIndex == "number"){
8603 return node.nodeIndex;
8605 var ns = this.nodes;
8606 for(var i = 0, len = ns.length; i < len; i++){
8617 * based on jquery fullcalendar
8621 Roo.bootstrap = Roo.bootstrap || {};
8623 * @class Roo.bootstrap.Calendar
8624 * @extends Roo.bootstrap.Component
8625 * Bootstrap Calendar class
8628 * Create a new Container
8629 * @param {Object} config The config object
8634 Roo.bootstrap.Calendar = function(config){
8635 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
8639 * Fires when a date is selected
8640 * @param {DatePicker} this
8641 * @param {Date} date The selected date
8645 * @event monthchange
8646 * Fires when the displayed month changes
8647 * @param {DatePicker} this
8648 * @param {Date} date The selected month
8650 'monthchange': true,
8653 * Fires when mouse over an event
8654 * @param {Calendar} this
8655 * @param {event} Event
8660 * Fires when the mouse leaves an
8661 * @param {Calendar} this
8667 * Fires when the mouse click an
8668 * @param {Calendar} this
8677 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
8680 * @cfg {Number} startDay
8681 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
8685 getAutoCreate : function(){
8688 var fc_button = function(name, corner, style, content ) {
8689 return Roo.apply({},{
8691 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
8693 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
8696 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
8704 style : 'width:100%',
8711 cls : 'fc-header-left',
8713 fc_button('prev', 'left', 'arrow', '‹' ),
8714 fc_button('next', 'right', 'arrow', '›' ),
8715 { tag: 'span', cls: 'fc-header-space' },
8716 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
8724 cls : 'fc-header-center',
8728 cls: 'fc-header-title',
8731 html : 'month / year'
8739 cls : 'fc-header-right',
8741 /* fc_button('month', 'left', '', 'month' ),
8742 fc_button('week', '', '', 'week' ),
8743 fc_button('day', 'right', '', 'day' )
8755 var cal_heads = function() {
8757 // fixme - handle this.
8759 for (var i =0; i < Date.dayNames.length; i++) {
8760 var d = Date.dayNames[i];
8763 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
8764 html : d.substring(0,3)
8768 ret[0].cls += ' fc-first';
8769 ret[6].cls += ' fc-last';
8772 var cal_cell = function(n) {
8775 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
8780 cls: 'fc-day-number',
8784 cls: 'fc-day-content',
8788 style: 'position: relative;' // height: 17px;
8800 var cal_rows = function() {
8803 for (var r = 0; r < 6; r++) {
8810 for (var i =0; i < Date.dayNames.length; i++) {
8811 var d = Date.dayNames[i];
8812 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
8815 row.cn[0].cls+=' fc-first';
8816 row.cn[0].cn[0].style = 'min-height:90px';
8817 row.cn[6].cls+=' fc-last';
8821 ret[0].cls += ' fc-first';
8822 ret[4].cls += ' fc-prev-last';
8823 ret[5].cls += ' fc-last';
8830 cls: 'fc-border-separate',
8831 style : 'width:100%',
8839 cls : 'fc-first fc-last',
8858 style : "position: relative;",
8861 cls : 'fc-view fc-view-month fc-grid',
8862 style : 'position: relative',
8863 unselectable : 'on',
8866 cls : 'fc-event-container',
8867 style : 'position:absolute;z-index:8;top:0;left:0;'
8885 initEvents : function()
8888 throw "can not find store for calendar";
8891 this.store = Roo.factory(this.store, Roo.data);
8892 this.store.on('load', this.onLoad, this);
8896 this.cells = this.el.select('.fc-day',true);
8897 //Roo.log(this.cells);
8898 this.textNodes = this.el.query('.fc-day-number');
8899 this.cells.addClassOnOver('fc-state-hover');
8901 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
8902 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
8903 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
8904 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
8906 this.on('monthchange', this.onMonthChange, this);
8908 this.update(new Date().clearTime());
8911 resize : function() {
8912 var sz = this.el.getSize();
8914 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
8915 this.el.select('.fc-day-content div',true).setHeight(34);
8920 showPrevMonth : function(e){
8921 this.update(this.activeDate.add("mo", -1));
8923 showToday : function(e){
8924 this.update(new Date().clearTime());
8927 showNextMonth : function(e){
8928 this.update(this.activeDate.add("mo", 1));
8932 showPrevYear : function(){
8933 this.update(this.activeDate.add("y", -1));
8937 showNextYear : function(){
8938 this.update(this.activeDate.add("y", 1));
8943 update : function(date)
8945 var vd = this.activeDate;
8946 this.activeDate = date;
8947 // if(vd && this.el){
8948 // var t = date.getTime();
8949 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
8950 // Roo.log('using add remove');
8952 // this.fireEvent('monthchange', this, date);
8954 // this.cells.removeClass("fc-state-highlight");
8955 // this.cells.each(function(c){
8956 // if(c.dateValue == t){
8957 // c.addClass("fc-state-highlight");
8958 // setTimeout(function(){
8959 // try{c.dom.firstChild.focus();}catch(e){}
8969 var days = date.getDaysInMonth();
8971 var firstOfMonth = date.getFirstDateOfMonth();
8972 var startingPos = firstOfMonth.getDay()-this.startDay;
8974 if(startingPos < this.startDay){
8978 var pm = date.add(Date.MONTH, -1);
8979 var prevStart = pm.getDaysInMonth()-startingPos;
8981 this.cells = this.el.select('.fc-day',true);
8982 this.textNodes = this.el.query('.fc-day-number');
8983 this.cells.addClassOnOver('fc-state-hover');
8985 var cells = this.cells.elements;
8986 var textEls = this.textNodes;
8988 Roo.each(cells, function(cell){
8989 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
8992 days += startingPos;
8994 // convert everything to numbers so it's fast
8996 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
8999 //Roo.log(prevStart);
9001 var today = new Date().clearTime().getTime();
9002 var sel = date.clearTime().getTime();
9003 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
9004 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
9005 var ddMatch = this.disabledDatesRE;
9006 var ddText = this.disabledDatesText;
9007 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
9008 var ddaysText = this.disabledDaysText;
9009 var format = this.format;
9011 var setCellClass = function(cal, cell){
9013 //Roo.log('set Cell Class');
9015 var t = d.getTime();
9021 cell.className += " fc-today";
9022 cell.className += " fc-state-highlight";
9023 cell.title = cal.todayText;
9026 // disable highlight in other month..
9027 //cell.className += " fc-state-highlight";
9032 cell.className = " fc-state-disabled";
9033 cell.title = cal.minText;
9037 cell.className = " fc-state-disabled";
9038 cell.title = cal.maxText;
9042 if(ddays.indexOf(d.getDay()) != -1){
9043 cell.title = ddaysText;
9044 cell.className = " fc-state-disabled";
9047 if(ddMatch && format){
9048 var fvalue = d.dateFormat(format);
9049 if(ddMatch.test(fvalue)){
9050 cell.title = ddText.replace("%0", fvalue);
9051 cell.className = " fc-state-disabled";
9055 if (!cell.initialClassName) {
9056 cell.initialClassName = cell.dom.className;
9059 cell.dom.className = cell.initialClassName + ' ' + cell.className;
9064 for(; i < startingPos; i++) {
9065 textEls[i].innerHTML = (++prevStart);
9066 d.setDate(d.getDate()+1);
9068 cells[i].className = "fc-past fc-other-month";
9069 setCellClass(this, cells[i]);
9074 for(; i < days; i++){
9075 intDay = i - startingPos + 1;
9076 textEls[i].innerHTML = (intDay);
9077 d.setDate(d.getDate()+1);
9079 cells[i].className = ''; // "x-date-active";
9080 setCellClass(this, cells[i]);
9084 for(; i < 42; i++) {
9085 textEls[i].innerHTML = (++extraDays);
9086 d.setDate(d.getDate()+1);
9088 cells[i].className = "fc-future fc-other-month";
9089 setCellClass(this, cells[i]);
9092 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
9094 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
9096 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
9097 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
9100 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
9101 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
9104 this.fireEvent('monthchange', this, date);
9108 if(!this.internalRender){
9109 var main = this.el.dom.firstChild;
9110 var w = main.offsetWidth;
9111 this.el.setWidth(w + this.el.getBorderWidth("lr"));
9112 Roo.fly(main).setWidth(w);
9113 this.internalRender = true;
9114 // opera does not respect the auto grow header center column
9115 // then, after it gets a width opera refuses to recalculate
9116 // without a second pass
9117 if(Roo.isOpera && !this.secondPass){
9118 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
9119 this.secondPass = true;
9120 this.update.defer(10, this, [date]);
9127 findCell : function(dt) {
9128 dt = dt.clearTime().getTime();
9130 this.cells.each(function(c){
9131 //Roo.log("check " +c.dateValue + '?=' + dt);
9132 if(c.dateValue == dt){
9142 findCells : function(ev) {
9143 var s = ev.start.clone().clearTime().getTime();
9145 var e= ev.end.clone().clearTime().getTime();
9148 this.cells.each(function(c){
9149 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
9151 if(c.dateValue > e){
9154 if(c.dateValue < s){
9163 findBestRow: function(cells)
9167 for (var i =0 ; i < cells.length;i++) {
9168 ret = Math.max(cells[i].rows || 0,ret);
9175 addItem : function(ev)
9177 // look for vertical location slot in
9178 var cells = this.findCells(ev);
9180 ev.row = this.findBestRow(cells);
9182 // work out the location.
9186 for(var i =0; i < cells.length; i++) {
9194 if (crow.start.getY() == cells[i].getY()) {
9196 crow.end = cells[i];
9212 for (var i = 0; i < cells.length;i++) {
9213 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
9217 this.calevents.push(ev);
9220 clearEvents: function() {
9222 if(!this.calevents){
9226 Roo.each(this.cells.elements, function(c){
9230 Roo.each(this.calevents, function(e) {
9231 Roo.each(e.els, function(el) {
9232 el.un('mouseenter' ,this.onEventEnter, this);
9233 el.un('mouseleave' ,this.onEventLeave, this);
9240 renderEvents: function()
9242 // first make sure there is enough space..
9244 this.cells.each(function(c) {
9246 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
9249 for (var e = 0; e < this.calevents.length; e++) {
9250 var ev = this.calevents[e];
9251 var cells = ev.cells;
9254 for(var i =0; i < rows.length; i++) {
9257 // how many rows should it span..
9260 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
9261 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
9263 unselectable : "on",
9266 cls: 'fc-event-inner',
9270 cls: 'fc-event-time',
9271 html : cells.length > 1 ? '' : ev.time
9275 cls: 'fc-event-title',
9276 html : String.format('{0}', ev.title)
9283 cls: 'ui-resizable-handle ui-resizable-e',
9284 html : '  '
9290 cfg.cls += ' fc-event-start';
9292 if ((i+1) == rows.length) {
9293 cfg.cls += ' fc-event-end';
9296 var ctr = this.el.select('.fc-event-container',true).first();
9297 var cg = ctr.createChild(cfg);
9299 cg.on('mouseenter' ,this.onEventEnter, this, ev);
9300 cg.on('mouseleave' ,this.onEventLeave, this, ev);
9301 cg.on('click', this.onEventClick, this, ev);
9305 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
9306 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
9308 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
9309 cg.setWidth(ebox.right - sbox.x -2);
9317 onEventEnter: function (e, el,event,d) {
9318 this.fireEvent('evententer', this, el, event);
9321 onEventLeave: function (e, el,event,d) {
9322 this.fireEvent('eventleave', this, el, event);
9325 onEventClick: function (e, el,event,d) {
9326 this.fireEvent('eventclick', this, el, event);
9329 onMonthChange: function () {
9333 onLoad: function () {
9336 //Roo.log('calendar onload');
9338 this.calevents = [];
9340 if(this.store.getCount() > 0){
9341 this.store.data.each(function(d){
9344 start: new Date(d.data.start_dt),
9345 end : new Date(d.data.end_dt),
9346 time : d.data.start_time,
9347 title : d.data.title,
9348 description : d.data.description,
9349 venue : d.data.venue
9354 this.renderEvents();
9367 * @class Roo.bootstrap.Popover
9368 * @extends Roo.bootstrap.Component
9369 * Bootstrap Popover class
9370 * @cfg {String} html contents of the popover (or false to use children..)
9371 * @cfg {String} title of popover (or false to hide)
9372 * @cfg {String} placement how it is placed
9373 * @cfg {String} trigger click || hover (or false to trigger manually)
9374 * @cfg {String} over what (parent or false to trigger manually.)
9377 * Create a new Popover
9378 * @param {Object} config The config object
9381 Roo.bootstrap.Popover = function(config){
9382 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
9385 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
9387 title: 'Fill in a title',
9390 placement : 'right',
9391 trigger : 'hover', // hover
9395 can_build_overlaid : false,
9397 getChildContainer : function()
9399 return this.el.select('.popover-content',true).first();
9402 getAutoCreate : function(){
9403 Roo.log('make popover?');
9405 cls : 'popover roo-dynamic',
9406 style: 'display:block',
9412 cls : 'popover-inner',
9416 cls: 'popover-title',
9420 cls : 'popover-content',
9431 setTitle: function(str)
9433 this.el.select('.popover-title',true).first().dom.innerHTML = str;
9435 setContent: function(str)
9437 this.el.select('.popover-content',true).first().dom.innerHTML = str;
9439 // as it get's added to the bottom of the page.
9440 onRender : function(ct, position)
9442 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
9444 var cfg = Roo.apply({}, this.getAutoCreate());
9448 cfg.cls += ' ' + this.cls;
9451 cfg.style = this.style;
9453 Roo.log("adding to ")
9454 this.el = Roo.get(document.body).createChild(cfg, position);
9460 initEvents : function()
9462 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
9463 this.el.enableDisplayMode('block');
9465 if (this.over === false) {
9468 if (this.triggers === false) {
9471 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9472 var triggers = this.trigger ? this.trigger.split(' ') : [];
9473 Roo.each(triggers, function(trigger) {
9475 if (trigger == 'click') {
9476 on_el.on('click', this.toggle, this);
9477 } else if (trigger != 'manual') {
9478 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
9479 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
9481 on_el.on(eventIn ,this.enter, this);
9482 on_el.on(eventOut, this.leave, this);
9493 toggle : function () {
9494 this.hoverState == 'in' ? this.leave() : this.enter();
9497 enter : function () {
9500 clearTimeout(this.timeout);
9502 this.hoverState = 'in'
9504 if (!this.delay || !this.delay.show) {
9509 this.timeout = setTimeout(function () {
9510 if (_t.hoverState == 'in') {
9515 leave : function() {
9516 clearTimeout(this.timeout);
9518 this.hoverState = 'out'
9520 if (!this.delay || !this.delay.hide) {
9525 this.timeout = setTimeout(function () {
9526 if (_t.hoverState == 'out') {
9532 show : function (on_el)
9535 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9538 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
9539 if (this.html !== false) {
9540 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
9542 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
9543 if (!this.title.length) {
9544 this.el.select('.popover-title',true).hide();
9547 var placement = typeof this.placement == 'function' ?
9548 this.placement.call(this, this.el, on_el) :
9551 var autoToken = /\s?auto?\s?/i;
9552 var autoPlace = autoToken.test(placement);
9554 placement = placement.replace(autoToken, '') || 'top';
9558 //this.el.setXY([0,0]);
9560 this.el.dom.style.display='block';
9561 this.el.addClass(placement);
9563 //this.el.appendTo(on_el);
9565 var p = this.getPosition();
9566 var box = this.el.getBox();
9571 var align = Roo.bootstrap.Popover.alignment[placement]
9572 this.el.alignTo(on_el, align[0],align[1]);
9573 //var arrow = this.el.select('.arrow',true).first();
9574 //arrow.set(align[2],
9576 this.el.addClass('in');
9577 this.hoverState = null;
9579 if (this.el.hasClass('fade')) {
9586 this.el.setXY([0,0]);
9587 this.el.removeClass('in');
9594 Roo.bootstrap.Popover.alignment = {
9595 'left' : ['r-l', [-10,0], 'right'],
9596 'right' : ['l-r', [10,0], 'left'],
9597 'bottom' : ['t-b', [0,10], 'top'],
9598 'top' : [ 'b-t', [0,-10], 'bottom']
9609 * @class Roo.bootstrap.Progress
9610 * @extends Roo.bootstrap.Component
9611 * Bootstrap Progress class
9612 * @cfg {Boolean} striped striped of the progress bar
9613 * @cfg {Boolean} active animated of the progress bar
9617 * Create a new Progress
9618 * @param {Object} config The config object
9621 Roo.bootstrap.Progress = function(config){
9622 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
9625 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
9630 getAutoCreate : function(){
9638 cfg.cls += ' progress-striped';
9642 cfg.cls += ' active';
9661 * @class Roo.bootstrap.ProgressBar
9662 * @extends Roo.bootstrap.Component
9663 * Bootstrap ProgressBar class
9664 * @cfg {Number} aria_valuenow aria-value now
9665 * @cfg {Number} aria_valuemin aria-value min
9666 * @cfg {Number} aria_valuemax aria-value max
9667 * @cfg {String} label label for the progress bar
9668 * @cfg {String} panel (success | info | warning | danger )
9669 * @cfg {String} role role of the progress bar
9670 * @cfg {String} sr_only text
9674 * Create a new ProgressBar
9675 * @param {Object} config The config object
9678 Roo.bootstrap.ProgressBar = function(config){
9679 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
9682 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
9686 aria_valuemax : 100,
9692 getAutoCreate : function()
9697 cls: 'progress-bar',
9698 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
9710 cfg.role = this.role;
9713 if(this.aria_valuenow){
9714 cfg['aria-valuenow'] = this.aria_valuenow;
9717 if(this.aria_valuemin){
9718 cfg['aria-valuemin'] = this.aria_valuemin;
9721 if(this.aria_valuemax){
9722 cfg['aria-valuemax'] = this.aria_valuemax;
9725 if(this.label && !this.sr_only){
9726 cfg.html = this.label;
9730 cfg.cls += ' progress-bar-' + this.panel;
9736 update : function(aria_valuenow)
9738 this.aria_valuenow = aria_valuenow;
9740 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
9755 * @class Roo.bootstrap.TabPanel
9756 * @extends Roo.bootstrap.Component
9757 * Bootstrap TabPanel class
9758 * @cfg {Boolean} active panel active
9759 * @cfg {String} html panel content
9760 * @cfg {String} tabId tab relate id
9764 * Create a new TabPanel
9765 * @param {Object} config The config object
9768 Roo.bootstrap.TabPanel = function(config){
9769 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
9772 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
9778 getAutoCreate : function(){
9782 html: this.html || ''
9786 cfg.cls += ' active';
9790 cfg.tabId = this.tabId;
9808 * @class Roo.bootstrap.DateField
9809 * @extends Roo.bootstrap.Input
9810 * Bootstrap DateField class
9811 * @cfg {Number} weekStart default 0
9812 * @cfg {Number} weekStart default 0
9813 * @cfg {Number} viewMode default empty, (months|years)
9814 * @cfg {Number} minViewMode default empty, (months|years)
9815 * @cfg {Number} startDate default -Infinity
9816 * @cfg {Number} endDate default Infinity
9817 * @cfg {Boolean} todayHighlight default false
9818 * @cfg {Boolean} todayBtn default false
9819 * @cfg {Boolean} calendarWeeks default false
9820 * @cfg {Object} daysOfWeekDisabled default empty
9822 * @cfg {Boolean} keyboardNavigation default true
9823 * @cfg {String} language default en
9826 * Create a new DateField
9827 * @param {Object} config The config object
9830 Roo.bootstrap.DateField = function(config){
9831 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
9834 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
9837 * @cfg {String} format
9838 * The default date format string which can be overriden for localization support. The format must be
9839 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
9843 * @cfg {String} altFormats
9844 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
9845 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
9847 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
9855 todayHighlight : false,
9861 keyboardNavigation: true,
9863 calendarWeeks: false,
9865 startDate: -Infinity,
9869 daysOfWeekDisabled: [],
9875 return new Date(Date.UTC.apply(Date, arguments));
9878 UTCToday: function()
9880 var today = new Date();
9881 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
9884 getDate: function() {
9885 var d = this.getUTCDate();
9886 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
9889 getUTCDate: function() {
9893 setDate: function(d) {
9894 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
9897 setUTCDate: function(d) {
9899 this.setValue(this.formatDate(this.date));
9902 onRender: function(ct, position)
9905 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
9907 this.language = this.language || 'en';
9908 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
9909 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
9911 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
9912 this.format = this.format || 'm/d/y';
9913 this.isInline = false;
9914 this.isInput = true;
9915 this.component = this.el.select('.add-on', true).first() || false;
9916 this.component = (this.component && this.component.length === 0) ? false : this.component;
9917 this.hasInput = this.component && this.inputEL().length;
9919 if (typeof(this.minViewMode === 'string')) {
9920 switch (this.minViewMode) {
9922 this.minViewMode = 1;
9925 this.minViewMode = 2;
9928 this.minViewMode = 0;
9933 if (typeof(this.viewMode === 'string')) {
9934 switch (this.viewMode) {
9947 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
9949 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
9951 this.picker().on('mousedown', this.onMousedown, this);
9952 this.picker().on('click', this.onClick, this);
9954 this.picker().addClass('datepicker-dropdown');
9956 this.startViewMode = this.viewMode;
9959 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
9960 if(!this.calendarWeeks){
9965 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
9966 v.attr('colspan', function(i, val){
9967 return parseInt(val) + 1;
9972 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
9974 this.setStartDate(this.startDate);
9975 this.setEndDate(this.endDate);
9977 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
9991 return this.el.select('.datepicker', true).first();
9996 var dowCnt = this.weekStart;
10005 if(this.calendarWeeks){
10013 while (dowCnt < this.weekStart + 7) {
10017 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
10021 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
10024 fillMonths: function()
10027 var months = this.picker().select('>.datepicker-months td', true).first();
10029 months.dom.innerHTML = '';
10035 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
10038 months.createChild(month);
10043 update: function(){
10045 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
10047 if (this.date < this.startDate) {
10048 this.viewDate = new Date(this.startDate);
10049 } else if (this.date > this.endDate) {
10050 this.viewDate = new Date(this.endDate);
10052 this.viewDate = new Date(this.date);
10059 var d = new Date(this.viewDate),
10060 year = d.getUTCFullYear(),
10061 month = d.getUTCMonth(),
10062 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
10063 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
10064 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
10065 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
10066 currentDate = this.date && this.date.valueOf(),
10067 today = this.UTCToday();
10069 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
10071 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
10073 // this.picker.select('>tfoot th.today').
10074 // .text(dates[this.language].today)
10075 // .toggle(this.todayBtn !== false);
10077 this.updateNavArrows();
10080 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
10082 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
10084 prevMonth.setUTCDate(day);
10086 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
10088 var nextMonth = new Date(prevMonth);
10090 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
10092 nextMonth = nextMonth.valueOf();
10094 var fillMonths = false;
10096 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
10098 while(prevMonth.valueOf() < nextMonth) {
10101 if (prevMonth.getUTCDay() === this.weekStart) {
10103 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
10111 if(this.calendarWeeks){
10112 // ISO 8601: First week contains first thursday.
10113 // ISO also states week starts on Monday, but we can be more abstract here.
10115 // Start of current week: based on weekstart/current date
10116 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
10117 // Thursday of this week
10118 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
10119 // First Thursday of year, year from thursday
10120 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
10121 // Calendar week: ms between thursdays, div ms per day, div 7 days
10122 calWeek = (th - yth) / 864e5 / 7 + 1;
10124 fillMonths.cn.push({
10132 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
10134 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
10137 if (this.todayHighlight &&
10138 prevMonth.getUTCFullYear() == today.getFullYear() &&
10139 prevMonth.getUTCMonth() == today.getMonth() &&
10140 prevMonth.getUTCDate() == today.getDate()) {
10141 clsName += ' today';
10144 if (currentDate && prevMonth.valueOf() === currentDate) {
10145 clsName += ' active';
10148 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
10149 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
10150 clsName += ' disabled';
10153 fillMonths.cn.push({
10155 cls: 'day ' + clsName,
10156 html: prevMonth.getDate()
10159 prevMonth.setDate(prevMonth.getDate()+1);
10162 var currentYear = this.date && this.date.getUTCFullYear();
10163 var currentMonth = this.date && this.date.getUTCMonth();
10165 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
10167 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
10168 v.removeClass('active');
10170 if(currentYear === year && k === currentMonth){
10171 v.addClass('active');
10174 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
10175 v.addClass('disabled');
10181 year = parseInt(year/10, 10) * 10;
10183 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
10185 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
10188 for (var i = -1; i < 11; i++) {
10189 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
10191 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
10199 showMode: function(dir) {
10201 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
10203 Roo.each(this.picker().select('>div',true).elements, function(v){
10204 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10207 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
10212 if(this.isInline) return;
10214 this.picker().removeClass(['bottom', 'top']);
10216 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
10218 * place to the top of element!
10222 this.picker().addClass('top');
10223 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10228 this.picker().addClass('bottom');
10230 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10233 parseDate : function(value){
10234 if(!value || value instanceof Date){
10237 var v = Date.parseDate(value, this.format);
10238 if (!v && this.useIso) {
10239 v = Date.parseDate(value, 'Y-m-d');
10241 if(!v && this.altFormats){
10242 if(!this.altFormatsArray){
10243 this.altFormatsArray = this.altFormats.split("|");
10245 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
10246 v = Date.parseDate(value, this.altFormatsArray[i]);
10252 formatDate : function(date, fmt){
10253 return (!date || !(date instanceof Date)) ?
10254 date : date.dateFormat(fmt || this.format);
10257 onFocus : function()
10259 Roo.bootstrap.DateField.superclass.onFocus.call(this);
10263 onBlur : function()
10265 Roo.bootstrap.DateField.superclass.onBlur.call(this);
10271 this.picker().show();
10278 if(this.isInline) return;
10279 this.picker().hide();
10280 this.viewMode = this.startViewMode;
10285 onMousedown: function(e){
10286 e.stopPropagation();
10287 e.preventDefault();
10290 keyup: function(e){
10291 Roo.bootstrap.DateField.superclass.keyup.call(this);
10296 fireKey: function(e){
10297 if (!this.picker().isVisible()){
10298 if (e.keyCode == 27) // allow escape to hide and re-show picker
10302 var dateChanged = false,
10304 newDate, newViewDate;
10308 e.preventDefault();
10312 if (!this.keyboardNavigation) break;
10313 dir = e.keyCode == 37 ? -1 : 1;
10316 newDate = this.moveYear(this.date, dir);
10317 newViewDate = this.moveYear(this.viewDate, dir);
10318 } else if (e.shiftKey){
10319 newDate = this.moveMonth(this.date, dir);
10320 newViewDate = this.moveMonth(this.viewDate, dir);
10322 newDate = new Date(this.date);
10323 newDate.setUTCDate(this.date.getUTCDate() + dir);
10324 newViewDate = new Date(this.viewDate);
10325 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
10327 if (this.dateWithinRange(newDate)){
10328 this.date = newDate;
10329 this.viewDate = newViewDate;
10330 this.setValue(this.formatDate(this.date));
10332 e.preventDefault();
10333 dateChanged = true;
10338 if (!this.keyboardNavigation) break;
10339 dir = e.keyCode == 38 ? -1 : 1;
10341 newDate = this.moveYear(this.date, dir);
10342 newViewDate = this.moveYear(this.viewDate, dir);
10343 } else if (e.shiftKey){
10344 newDate = this.moveMonth(this.date, dir);
10345 newViewDate = this.moveMonth(this.viewDate, dir);
10347 newDate = new Date(this.date);
10348 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
10349 newViewDate = new Date(this.viewDate);
10350 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
10352 if (this.dateWithinRange(newDate)){
10353 this.date = newDate;
10354 this.viewDate = newViewDate;
10355 this.setValue(this.formatDate(this.date));
10357 e.preventDefault();
10358 dateChanged = true;
10362 this.setValue(this.formatDate(this.date));
10364 e.preventDefault();
10367 this.setValue(this.formatDate(this.date));
10374 onClick: function(e) {
10375 e.stopPropagation();
10376 e.preventDefault();
10378 var target = e.getTarget();
10380 if(target.nodeName.toLowerCase() === 'i'){
10381 target = Roo.get(target).dom.parentNode;
10384 var nodeName = target.nodeName;
10385 var className = target.className;
10386 var html = target.innerHTML;
10388 switch(nodeName.toLowerCase()) {
10390 switch(className) {
10396 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
10397 switch(this.viewMode){
10399 this.viewDate = this.moveMonth(this.viewDate, dir);
10403 this.viewDate = this.moveYear(this.viewDate, dir);
10409 var date = new Date();
10410 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
10412 this.setValue(this.formatDate(this.date));
10418 if (className.indexOf('disabled') === -1) {
10419 this.viewDate.setUTCDate(1);
10420 if (className.indexOf('month') !== -1) {
10421 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
10423 var year = parseInt(html, 10) || 0;
10424 this.viewDate.setUTCFullYear(year);
10433 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
10434 var day = parseInt(html, 10) || 1;
10435 var year = this.viewDate.getUTCFullYear(),
10436 month = this.viewDate.getUTCMonth();
10438 if (className.indexOf('old') !== -1) {
10445 } else if (className.indexOf('new') !== -1) {
10453 this.date = this.UTCDate(year, month, day,0,0,0,0);
10454 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
10456 this.setValue(this.formatDate(this.date));
10463 setStartDate: function(startDate){
10464 this.startDate = startDate || -Infinity;
10465 if (this.startDate !== -Infinity) {
10466 this.startDate = this.parseDate(this.startDate);
10469 this.updateNavArrows();
10472 setEndDate: function(endDate){
10473 this.endDate = endDate || Infinity;
10474 if (this.endDate !== Infinity) {
10475 this.endDate = this.parseDate(this.endDate);
10478 this.updateNavArrows();
10481 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
10482 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
10483 if (typeof(this.daysOfWeekDisabled) !== 'object') {
10484 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
10486 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
10487 return parseInt(d, 10);
10490 this.updateNavArrows();
10493 updateNavArrows: function() {
10494 var d = new Date(this.viewDate),
10495 year = d.getUTCFullYear(),
10496 month = d.getUTCMonth();
10498 Roo.each(this.picker().select('.prev', true).elements, function(v){
10500 switch (this.viewMode) {
10503 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
10509 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
10516 Roo.each(this.picker().select('.next', true).elements, function(v){
10518 switch (this.viewMode) {
10521 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
10527 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
10535 moveMonth: function(date, dir){
10536 if (!dir) return date;
10537 var new_date = new Date(date.valueOf()),
10538 day = new_date.getUTCDate(),
10539 month = new_date.getUTCMonth(),
10540 mag = Math.abs(dir),
10542 dir = dir > 0 ? 1 : -1;
10545 // If going back one month, make sure month is not current month
10546 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
10548 return new_date.getUTCMonth() == month;
10550 // If going forward one month, make sure month is as expected
10551 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
10553 return new_date.getUTCMonth() != new_month;
10555 new_month = month + dir;
10556 new_date.setUTCMonth(new_month);
10557 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
10558 if (new_month < 0 || new_month > 11)
10559 new_month = (new_month + 12) % 12;
10561 // For magnitudes >1, move one month at a time...
10562 for (var i=0; i<mag; i++)
10563 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
10564 new_date = this.moveMonth(new_date, dir);
10565 // ...then reset the day, keeping it in the new month
10566 new_month = new_date.getUTCMonth();
10567 new_date.setUTCDate(day);
10569 return new_month != new_date.getUTCMonth();
10572 // Common date-resetting loop -- if date is beyond end of month, make it
10575 new_date.setUTCDate(--day);
10576 new_date.setUTCMonth(new_month);
10581 moveYear: function(date, dir){
10582 return this.moveMonth(date, dir*12);
10585 dateWithinRange: function(date){
10586 return date >= this.startDate && date <= this.endDate;
10590 remove: function() {
10591 this.picker().remove();
10596 Roo.apply(Roo.bootstrap.DateField, {
10607 html: '<i class="icon-arrow-left"/>'
10617 html: '<i class="icon-arrow-right"/>'
10659 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
10660 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
10661 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
10662 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
10663 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
10676 navFnc: 'FullYear',
10681 navFnc: 'FullYear',
10686 Roo.apply(Roo.bootstrap.DateField, {
10690 cls: 'datepicker dropdown-menu',
10694 cls: 'datepicker-days',
10698 cls: 'table-condensed',
10700 Roo.bootstrap.DateField.head,
10704 Roo.bootstrap.DateField.footer
10711 cls: 'datepicker-months',
10715 cls: 'table-condensed',
10717 Roo.bootstrap.DateField.head,
10718 Roo.bootstrap.DateField.content,
10719 Roo.bootstrap.DateField.footer
10726 cls: 'datepicker-years',
10730 cls: 'table-condensed',
10732 Roo.bootstrap.DateField.head,
10733 Roo.bootstrap.DateField.content,
10734 Roo.bootstrap.DateField.footer
10753 * @class Roo.bootstrap.Label
10754 * @extends Roo.bootstrap.Component
10755 * Bootstrap Label class
10756 * @cfg {String} html The label content
10757 * @cfg {String} tag (span|label|p) The tag of this element, default label
10760 * Create a new Label
10761 * @param {Object} config The config object
10764 Roo.bootstrap.Label = function(config){
10765 Roo.bootstrap.Label.superclass.constructor.call(this, config);
10768 Roo.extend(Roo.bootstrap.Label, Roo.bootstrap.Component, {
10773 getAutoCreate : function(){
10777 html: this.html || ''
10782 cfg.cls = this.cls;