All of my work from commits: dd4a194, 692644a, 4a60203, 5de46bc, 152042d, 64a2d4e...
[philo.git] / contrib / gilbert / media / gilbert / lib / ui / forms.js
1 Ext.ns('Gilbert.lib.ui.forms');
2
3
4 Gilbert.lib.ui.forms.ClearableComboBox = Ext.extend(Ext.form.ComboBox, {
5         
6         initComponent: function () {
7                 Gilbert.lib.ui.forms.ClearableComboBox.superclass.initComponent.call(this);
8                 
9                 this.triggerConfig = {
10                         tag: 'span',
11                         cls: 'x-form-twin-triggers',
12                         cn: [
13                                 {
14                                         tag: 'img',
15                                         src: Ext.BLANK_IMAGE_URL,
16                                         alt: '',
17                                         cls: 'x-form-trigger x-form-clear-trigger', 
18                                 },
19                                 {
20                                         tag: 'img',
21                                         src: Ext.BLANK_IMAGE_URL,
22                                         alt: '',
23                                         cls: 'x-form-trigger ' + this.triggerClass,
24                                 },
25                         ],
26                 };
27         },
28         
29         afterRender: function () {
30                 Gilbert.lib.ui.forms.ClearableComboBox.superclass.afterRender.call(this);
31                 
32                 if (this.value && this.allowBlank) {
33                         this.triggers[0].show();
34                 } else {
35                         this.triggers[0].hide();
36                 }
37         },
38         
39         initTrigger: function () {
40                 Ext.form.TwinTriggerField.prototype.initTrigger.call(this);
41         },
42         
43         getTriggerWidth: function () {
44                 Ext.form.TwinTriggerField.prototype.getTriggerWidth.call(this);
45         },
46         
47         onTrigger2Click: function () {
48                 this.onTriggerClick();
49         },
50         
51         onTrigger1Click: function () {
52                 this.clearValue();
53                 this.triggers[0].hide();
54         },
55         
56         setValue: function (v) {
57                 Gilbert.lib.ui.forms.ClearableComboBox.superclass.setValue.call(this, v);
58                 
59                 if (this.value && this.allowBlank) {
60                         this.triggers[0].show();
61                 } else {
62                         this.triggers[0].hide();
63                 }
64         },
65         
66         onDestroy: function () {
67                 Ext.destroy(this.triggers);
68                 
69                 Gilbert.lib.ui.forms.ClearableComboBox.superclass.onDestroy.call(this);
70         },
71         
72 });
73 Ext.reg('gilbertclearablecombo', Gilbert.lib.ui.forms.ClearableComboBox);
74
75
76 Gilbert.lib.ui.forms.ModelChoiceField = Ext.extend(Gilbert.lib.ui.forms.ClearableComboBox, {
77         
78         model_app_label: undefined,
79         
80         model_name: undefined,
81         
82         model_filters: {},
83         
84         initComponent: function () {
85                 if (!this.model) {
86                         this.model = Gilbert.get_model(this.model_app_label, this.model_name);
87                 }
88                 if (!this.store) {
89                         if (!this.model && this.backup_store) {
90                                 this.store = this.backup_store;
91                         } else if (this.model) {
92                                 this.store = this.model.create_store({
93                                         baseParams: {
94                                                 filters: this.model_filters,
95                                         },
96                                 });
97                                 this.valueField = 'pk';
98                                 this.displayField = '__unicode__';
99                         
100                                 this.on('beforequery', function () {
101                                         delete this.lastQuery;
102                                 }, this);
103                                 this.store.on('load', function (store, records, options) {
104                                         this.store_loaded = true;
105                                 }, this, {single: true});
106                                 this.store.load();
107                                 
108                                 this.on('render', function () {
109                                         var outer = this;
110                                         this.dropTarget = new Ext.dd.DropTarget(this.el, {
111                                                 ddGroup: outer.model.drag_drop_group,
112                                                 notifyEnter: function (source, e, data) {
113                                                         outer.el.highlight();
114                                                         return Ext.dd.DropTarget.prototype.notifyEnter.call(this);
115                                                 },
116                                                 notifyDrop: function (source, e, data) {
117                                                         outer.setValue(data.selections[0].id);
118                                                         return true;
119                                                 },
120                                         });
121                                 }, this);
122                         }
123                 }
124                 Gilbert.lib.ui.forms.ModelChoiceField.superclass.initComponent.call(this);
125         },
126         
127         setValue: function (v) {
128                 if (this.model && !this.store_loaded) {
129                         this.el.dom.value = this.loadingText;
130                         this.store.on('load', this.setValue.createDelegate(this, [v]), null, {single: true});
131                         return;
132                 }
133                 return Gilbert.lib.ui.forms.ModelChoiceField.superclass.setValue.call(this, v);
134         }
135         
136 });
137 Ext.reg('gilbertmodelchoicefield', Gilbert.lib.ui.forms.ModelChoiceField);
138
139
140 Gilbert.lib.ui.forms.MultipleChoiceField = Ext.extend(Ext.ux.form.SuperBoxSelect, {});
141 Ext.reg('gilbertmultiplechoicefield', Gilbert.lib.ui.forms.MultipleChoiceField);
142
143
144 Gilbert.lib.ui.forms.ModelMultipleChoiceField = Ext.extend(Gilbert.lib.ui.forms.MultipleChoiceField, {});
145 Ext.reg('gilbertmodelmultiplechoicefield', Gilbert.lib.ui.forms.ModelMultipleChoiceField);
146
147
148 /*
149 Gilbert.lib.ui.DateTimeField is derived from revision 813 of Ext.ux.form.DateTime by Ing. Jozef Sakáloš as posted at http://extjs.com/forum/showthread.php?t=22661. 
150 It, and the original, is licensed under the GNU LGPL version 3.0 (http://www.gnu.org/licenses/lgpl.html).
151 */
152
153 /**
154  * Creates new DateTimeField
155  * @constructor
156  * @param {Object} config A config object
157  */
158 Gilbert.lib.ui.DateTimeField = Ext.extend(Ext.form.Field, {
159         /**
160          * @cfg {Function} dateValidator A custom validation function to be called during date field
161          * validation (defaults to null)
162          */
163         dateValidator: null
164         /**
165          * @cfg {String/Object} defaultAutoCreate DomHelper element spec
166          * Let superclass to create hidden field instead of textbox. Hidden will be submittend to server
167          */
168         ,
169         defaultAutoCreate: {
170                 tag: 'input',
171                 type: 'hidden'
172         }
173         /**
174          * @cfg {String} dtSeparator Date - Time separator. Used to split date and time (defaults to ' ' (space))
175          */
176         ,
177         dtSeparator: ' '
178         /**
179          * @cfg {String} hiddenFormat Format of datetime used to store value in hidden field
180          * and submitted to server (defaults to 'Y-m-d H:i:s' that is mysql format)
181          */
182         ,
183         hiddenFormat: 'Y-m-d H:i:s'
184         /**
185          * @cfg {Boolean} otherToNow Set other field to now() if not explicly filled in (defaults to true)
186          */
187         ,
188         otherToNow: true
189         /**
190          * @cfg {Boolean} emptyToNow Set field value to now on attempt to set empty value.
191          * If it is true then setValue() sets value of field to current date and time (defaults to false)
192          */
193         /**
194          * @cfg {String} timePosition Where the time field should be rendered. 'right' is suitable for forms
195          * and 'below' is suitable if the field is used as the grid editor (defaults to 'right')
196          */
197         ,
198         timePosition: 'right'
199         // valid values:'below', 'right'
200         /**
201          * @cfg {Function} timeValidator A custom validation function to be called during time field
202          * validation (defaults to null)
203          */
204         ,
205         timeValidator: null
206         /**
207          * @cfg {Number} timeWidth Width of time field in pixels (defaults to 100)
208          */
209         ,
210         timeWidth: 100
211         /**
212          * @cfg {String} dateFormat Format of DateField. Can be localized. (defaults to 'm/y/d')
213          */
214         ,
215         dateFormat: 'm/d/y'
216         /**
217          * @cfg {String} timeFormat Format of TimeField. Can be localized. (defaults to 'g:i A')
218          */
219         ,
220         timeFormat: 'g:i A'
221         /**
222          * @cfg {Object} dateConfig Config for DateField constructor.
223          */
224         /**
225          * @cfg {Object} timeConfig Config for TimeField constructor.
226          */
227
228         // {{{
229         /**
230          * @private
231          * creates DateField and TimeField and installs the necessary event handlers
232          */
233         ,
234         initComponent: function() {
235                 // call parent initComponent
236                 Gilbert.lib.ui.DateTimeField.superclass.initComponent.call(this);
237                 
238                 // create DateField
239                 var dateConfig = Ext.apply({},
240                 {
241                         id: this.id + '-date'
242                         ,
243                         format: this.dateFormat || Ext.form.DateField.prototype.format
244                         ,
245                         width: this.timeWidth
246                         ,
247                         selectOnFocus: this.selectOnFocus
248                         ,
249                         validator: this.dateValidator
250                         ,
251                         listeners: {
252                                 blur: {
253                                         scope: this,
254                                         fn: this.onBlur
255                                 }
256                                 ,
257                                 focus: {
258                                         scope: this,
259                                         fn: this.onFocus
260                                 }
261                         }
262                 },
263                 this.dateConfig);
264                 this.df = new Ext.form.DateField(dateConfig);
265                 this.df.ownerCt = this;
266                 delete(this.dateFormat);
267                 
268                 // create TimeField
269                 var timeConfig = Ext.apply({},
270                 {
271                         id: this.id + '-time'
272                         ,
273                         format: this.timeFormat || Ext.form.TimeField.prototype.format
274                         ,
275                         width: this.timeWidth
276                         ,
277                         selectOnFocus: this.selectOnFocus
278                         ,
279                         validator: this.timeValidator
280                         ,
281                         listeners: {
282                                 blur: {
283                                         scope: this,
284                                         fn: this.onBlur
285                                 }
286                                 ,
287                                 focus: {
288                                         scope: this,
289                                         fn: this.onFocus
290                                 }
291                         }
292                 },
293                 this.timeConfig);
294                 this.tf = new Ext.form.TimeField(timeConfig);
295                 this.tf.ownerCt = this;
296                 delete(this.timeFormat);
297                 
298                 // relay events
299                 this.relayEvents(this.df, ['focus', 'specialkey', 'invalid', 'valid']);
300                 this.relayEvents(this.tf, ['focus', 'specialkey', 'invalid', 'valid']);
301                 
302                 this.on('specialkey', this.onSpecialKey, this);
303                 
304         }
305         // eo function initComponent
306         // }}}
307         // {{{
308         /**
309          * @private
310          * Renders underlying DateField and TimeField and provides a workaround for side error icon bug
311          */
312         ,
313         onRender: function(ct, position) {
314                 // don't run more than once
315                 if (this.isRendered) {
316                         return;
317                 }
318                 
319                 // render underlying hidden field
320                 Gilbert.lib.ui.DateTimeField.superclass.onRender.call(this, ct, position);
321                 
322                 // render DateField and TimeField
323                 // create bounding table
324                 var t;
325                 if ('below' === this.timePosition || 'bellow' === this.timePosition) {
326                         t = Ext.DomHelper.append(ct, {
327                                 tag: 'table',
328                                 style: 'border-collapse:collapse',
329                                 children: [
330                                 {
331                                         tag: 'tr',
332                                         children: [{
333                                                 tag: 'td',
334                                                 style: 'padding-bottom:1px',
335                                                 cls: 'ux-datetime-date'
336                                         }]
337                                 }
338                                 ,
339                                 {
340                                         tag: 'tr',
341                                         children: [{
342                                                 tag: 'td',
343                                                 cls: 'ux-datetime-time'
344                                         }]
345                                 }
346                                 ]
347                         },
348                         true);
349                 }
350                 else {
351                         t = Ext.DomHelper.append(ct, {
352                                 tag: 'table',
353                                 style: 'border-collapse:collapse',
354                                 children: [
355                                 {
356                                         tag: 'tr',
357                                         children: [
358                                         {
359                                                 tag: 'td',
360                                                 style: 'padding-right:4px',
361                                                 cls: 'ux-datetime-date'
362                                         },
363                                         {
364                                                 tag: 'td',
365                                                 cls: 'ux-datetime-time'
366                                         }
367                                         ]
368                                 }
369                                 ]
370                         },
371                         true);
372                 }
373                 
374                 this.tableEl = t;
375                 this.wrap = t.wrap({
376                         cls: 'x-form-field-wrap'
377                 });
378                 //                this.wrap = t.wrap();
379                 this.wrap.on("mousedown", this.onMouseDown, this, {
380                         delay: 10
381                 });
382                 
383                 // render DateField & TimeField
384                 this.df.render(t.child('td.ux-datetime-date'));
385                 this.tf.render(t.child('td.ux-datetime-time'));
386                 
387                 // workaround for IE trigger misalignment bug
388                 // see http://extjs.com/forum/showthread.php?p=341075#post341075
389                 //                if(Ext.isIE && Ext.isStrict) {
390                 //                        t.select('input').applyStyles({top:0});
391                 //                }
392                 this.df.el.swallowEvent(['keydown', 'keypress']);
393                 this.tf.el.swallowEvent(['keydown', 'keypress']);
394                 
395                 // create icon for side invalid errorIcon
396                 if ('side' === this.msgTarget) {
397                         var elp = this.el.findParent('.x-form-element', 10, true);
398                         if (elp) {
399                                 this.errorIcon = elp.createChild({
400                                         cls: 'x-form-invalid-icon'
401                                 });
402                         }
403                         
404                         var o = {
405                                 errorIcon: this.errorIcon
406                                 ,
407                                 msgTarget: 'side'
408                                 ,
409                                 alignErrorIcon: this.alignErrorIcon.createDelegate(this)
410                         };
411                         Ext.apply(this.df, o);
412                         Ext.apply(this.tf, o);
413                         //                        this.df.errorIcon = this.errorIcon;
414                         //                        this.tf.errorIcon = this.errorIcon;
415                 }
416                 
417                 // setup name for submit
418                 this.el.dom.name = this.hiddenName || this.name || this.id;
419                 
420                 // prevent helper fields from being submitted
421                 this.df.el.dom.removeAttribute("name");
422                 this.tf.el.dom.removeAttribute("name");
423                 
424                 // we're rendered flag
425                 this.isRendered = true;
426                 
427                 // update hidden field
428                 this.updateHidden();
429                 
430         }
431         // eo function onRender
432         // }}}
433         // {{{
434         /**
435          * @private
436          */
437         ,
438         adjustSize: Ext.BoxComponent.prototype.adjustSize
439         // }}}
440         // {{{
441         /**
442          * @private
443          */
444         ,
445         alignErrorIcon: function() {
446                 this.errorIcon.alignTo(this.tableEl, 'tl-tr', [2, 0]);
447         }
448         // }}}
449         // {{{
450         /**
451          * @private initializes internal dateValue
452          */
453         ,
454         initDateValue: function() {
455                 this.dateValue = this.otherToNow ? new Date() : new Date(1970, 0, 1, 0, 0, 0);
456         }
457         // }}}
458         // {{{
459         /**
460          * Calls clearInvalid on the DateField and TimeField
461          */
462         ,
463         clearInvalid: function() {
464                 this.df.clearInvalid();
465                 this.tf.clearInvalid();
466         }
467         // eo function clearInvalid
468         // }}}
469         // {{{
470         /**
471          * Calls markInvalid on both DateField and TimeField
472          * @param {String} msg Invalid message to display
473          */
474         ,
475         markInvalid: function(msg) {
476                 this.df.markInvalid(msg);
477                 this.tf.markInvalid(msg);
478         }
479         // eo function markInvalid
480         // }}}
481         // {{{
482         /**
483          * @private
484          * called from Component::destroy. 
485          * Destroys all elements and removes all listeners we've created.
486          */
487         ,
488         beforeDestroy: function() {
489                 if (this.isRendered) {
490                         //                        this.removeAllListeners();
491                         this.wrap.removeAllListeners();
492                         this.wrap.remove();
493                         this.tableEl.remove();
494                         this.df.destroy();
495                         this.tf.destroy();
496                 }
497         }
498         // eo function beforeDestroy
499         // }}}
500         // {{{
501         /**
502          * Disable this component.
503          * @return {Ext.Component} this
504          */
505         ,
506         disable: function() {
507                 if (this.isRendered) {
508                         this.df.disabled = this.disabled;
509                         this.df.onDisable();
510                         this.tf.onDisable();
511                 }
512                 this.disabled = true;
513                 this.df.disabled = true;
514                 this.tf.disabled = true;
515                 this.fireEvent("disable", this);
516                 return this;
517         }
518         // eo function disable
519         // }}}
520         // {{{
521         /**
522          * Enable this component.
523          * @return {Ext.Component} this
524          */
525         ,
526         enable: function() {
527                 if (this.rendered) {
528                         this.df.onEnable();
529                         this.tf.onEnable();
530                 }
531                 this.disabled = false;
532                 this.df.disabled = false;
533                 this.tf.disabled = false;
534                 this.fireEvent("enable", this);
535                 return this;
536         }
537         // eo function enable
538         // }}}
539         // {{{
540         /**
541          * @private Focus date filed
542          */
543         ,
544         focus: function() {
545                 this.df.focus();
546         }
547         // eo function focus
548         // }}}
549         // {{{
550         /**
551          * @private
552          */
553         ,
554         getPositionEl: function() {
555                 return this.wrap;
556         }
557         // }}}
558         // {{{
559         /**
560          * @private
561          */
562         ,
563         getResizeEl: function() {
564                 return this.wrap;
565         }
566         // }}}
567         // {{{
568         /**
569          * @return {Date/String} Returns value of this field
570          */
571         ,
572         getValue: function() {
573                 // create new instance of date
574                 return this.dateValue ? new Date(this.dateValue) : '';
575         }
576         // eo function getValue
577         // }}}
578         // {{{
579         /**
580          * @return {Boolean} true = valid, false = invalid
581          * @private Calls isValid methods of underlying DateField and TimeField and returns the result
582          */
583         ,
584         isValid: function() {
585                 return this.df.isValid() && this.tf.isValid();
586         }
587         // eo function isValid
588         // }}}
589         // {{{
590         /**
591          * Returns true if this component is visible
592          * @return {boolean} 
593          */
594         ,
595         isVisible: function() {
596                 return this.df.rendered && this.df.getActionEl().isVisible();
597         }
598         // eo function isVisible
599         // }}}
600         // {{{
601         /** 
602          * @private Handles blur event
603          */
604         ,
605         onBlur: function(f) {
606                 // called by both DateField and TimeField blur events
607                 // revert focus to previous field if clicked in between
608                 if (this.wrapClick) {
609                         f.focus();
610                         this.wrapClick = false;
611                 }
612                 
613                 // update underlying value
614                 if (f === this.df) {
615                         this.updateDate();
616                 }
617                 else {
618                         this.updateTime();
619                 }
620                 this.updateHidden();
621                 
622                 this.validate();
623                 
624                 // fire events later
625                 (function() {
626                         if (!this.df.hasFocus && !this.tf.hasFocus) {
627                                 var v = this.getValue();
628                                 if (String(v) !== String(this.startValue)) {
629                                         this.fireEvent("change", this, v, this.startValue);
630                                 }
631                                 this.hasFocus = false;
632                                 this.fireEvent('blur', this);
633                         }
634                 }).defer(100, this);
635                 
636         }
637         // eo function onBlur
638         // }}}
639         // {{{
640         /**
641          * @private Handles focus event
642          */
643         ,
644         onFocus: function() {
645                 if (!this.hasFocus) {
646                         this.hasFocus = true;
647                         this.startValue = this.getValue();
648                         this.fireEvent("focus", this);
649                 }
650         }
651         // }}}
652         // {{{
653         /**
654          * @private Just to prevent blur event when clicked in the middle of fields
655          */
656         ,
657         onMouseDown: function(e) {
658                 if (!this.disabled) {
659                         this.wrapClick = 'td' === e.target.nodeName.toLowerCase();
660                 }
661         }
662         // }}}
663         // {{{
664         /**
665          * @private
666          * Handles Tab and Shift-Tab events
667          */
668         ,
669         onSpecialKey: function(t, e) {
670                 var key = e.getKey();
671                 if (key === e.TAB) {
672                         if (t === this.df && !e.shiftKey) {
673                                 e.stopEvent();
674                                 this.tf.focus();
675                         }
676                         if (t === this.tf && e.shiftKey) {
677                                 e.stopEvent();
678                                 this.df.focus();
679                         }
680                         this.updateValue();
681                 }
682                 // otherwise it misbehaves in editor grid
683                 if (key === e.ENTER) {
684                         this.updateValue();
685                 }
686                 
687         }
688         // eo function onSpecialKey
689         // }}}
690         // {{{
691         /**
692          * Resets the current field value to the originally loaded value 
693          * and clears any validation messages. See Ext.form.BasicForm.trackResetOnLoad
694          */
695         ,
696         reset: function() {
697                 this.df.setValue(this.originalValue);
698                 this.tf.setValue(this.originalValue);
699         }
700         // eo function reset
701         // }}}
702         // {{{
703         /**
704          * @private Sets the value of DateField
705          */
706         ,
707         setDate: function(date) {
708                 this.df.setValue(date);
709         }
710         // eo function setDate
711         // }}}
712         // {{{
713         /** 
714          * @private Sets the value of TimeField
715          */
716         ,
717         setTime: function(date) {
718                 this.tf.setValue(date);
719         }
720         // eo function setTime
721         // }}}
722         // {{{
723         /**
724          * @private
725          * Sets correct sizes of underlying DateField and TimeField
726          * With workarounds for IE bugs
727          */
728         ,
729         setSize: function(w, h) {
730                 if (!w) {
731                         return;
732                 }
733                 if ('below' === this.timePosition) {
734                         this.df.setSize(w, h);
735                         this.tf.setSize(w, h);
736                         if (Ext.isIE) {
737                                 this.df.el.up('td').setWidth(w);
738                                 this.tf.el.up('td').setWidth(w);
739                         }
740                 }
741                 else {
742                         this.df.setSize(w - this.timeWidth - 4, h);
743                         this.tf.setSize(this.timeWidth, h);
744                         
745                         if (Ext.isIE) {
746                                 this.df.el.up('td').setWidth(w - this.timeWidth - 4);
747                                 this.tf.el.up('td').setWidth(this.timeWidth);
748                         }
749                 }
750         }
751         // eo function setSize
752         // }}}
753         // {{{
754         /**
755          * @param {Mixed} val Value to set
756          * Sets the value of this field
757          */
758         ,
759         setValue: function(val) {
760                 if (!val && true === this.emptyToNow) {
761                         this.setValue(new Date());
762                         return;
763                 }
764                 else if (!val) {
765                         this.setDate('');
766                         this.setTime('');
767                         this.updateValue();
768                         return;
769                 }
770                 if ('number' === typeof val) {
771                         val = new Date(val);
772                 }
773                 else if ('string' === typeof val && this.hiddenFormat) {
774                         val = Date.parseDate(val, this.hiddenFormat);
775                 }
776                 val = val ? val: new Date(1970, 0, 1, 0, 0, 0);
777                 var da;
778                 if (val instanceof Date) {
779                         this.setDate(val);
780                         this.setTime(val);
781                         this.dateValue = new Date(Ext.isIE ? val.getTime() : val);
782                 }
783                 else {
784                         da = val.split(this.dtSeparator);
785                         this.setDate(da[0]);
786                         if (da[1]) {
787                                 if (da[2]) {
788                                         // add am/pm part back to time
789                                         da[1] += da[2];
790                                 }
791                                 this.setTime(da[1]);
792                         }
793                 }
794                 this.updateValue();
795         }
796         // eo function setValue
797         // }}}
798         // {{{
799         /**
800          * Hide or show this component by boolean
801          * @return {Ext.Component} this
802          */
803         ,
804         setVisible: function(visible) {
805                 if (visible) {
806                         this.df.show();
807                         this.tf.show();
808                 } else {
809                         this.df.hide();
810                         this.tf.hide();
811                 }
812                 return this;
813         }
814         // eo function setVisible
815         // }}}
816         //{{{
817         ,
818         show: function() {
819                 return this.setVisible(true);
820         }
821         // eo function show
822         //}}}
823         //{{{
824         ,
825         hide: function() {
826                 return this.setVisible(false);
827         }
828         // eo function hide
829         //}}}
830         // {{{
831         /**
832          * @private Updates the date part
833          */
834         ,
835         updateDate: function() {
836                 
837                 var d = this.df.getValue();
838                 if (d) {
839                         if (! (this.dateValue instanceof Date)) {
840                                 this.initDateValue();
841                                 if (!this.tf.getValue()) {
842                                         this.setTime(this.dateValue);
843                                 }
844                         }
845                         this.dateValue.setMonth(0);
846                         // because of leap years
847                         this.dateValue.setFullYear(d.getFullYear());
848                         this.dateValue.setMonth(d.getMonth(), d.getDate());
849                         //                        this.dateValue.setDate(d.getDate());
850                 }
851                 else {
852                         this.dateValue = '';
853                         this.setTime('');
854                 }
855         }
856         // eo function updateDate
857         // }}}
858         // {{{
859         /**
860          * @private
861          * Updates the time part
862          */
863         ,
864         updateTime: function() {
865                 var t = this.tf.getValue();
866                 if (t && !(t instanceof Date)) {
867                         t = Date.parseDate(t, this.tf.format);
868                 }
869                 if (t && !this.df.getValue()) {
870                         this.initDateValue();
871                         this.setDate(this.dateValue);
872                 }
873                 if (this.dateValue instanceof Date) {
874                         if (t) {
875                                 this.dateValue.setHours(t.getHours());
876                                 this.dateValue.setMinutes(t.getMinutes());
877                                 this.dateValue.setSeconds(t.getSeconds());
878                         }
879                         else {
880                                 this.dateValue.setHours(0);
881                                 this.dateValue.setMinutes(0);
882                                 this.dateValue.setSeconds(0);
883                         }
884                 }
885         }
886         // eo function updateTime
887         // }}}
888         // {{{
889         /**
890          * @private Updates the underlying hidden field value
891          */
892         ,
893         updateHidden: function() {
894                 if (this.isRendered) {
895                         var value = this.dateValue instanceof Date ? this.dateValue.format(this.hiddenFormat) : '';
896                         this.el.dom.value = value;
897                 }
898         }
899         // }}}
900         // {{{
901         /**
902          * @private Updates all of Date, Time and Hidden
903          */
904         ,
905         updateValue: function() {
906                 
907                 this.updateDate();
908                 this.updateTime();
909                 this.updateHidden();
910                 
911                 return;
912         }
913         // eo function updateValue
914         // }}}
915         // {{{
916         /**
917          * @return {Boolean} true = valid, false = invalid
918          * calls validate methods of DateField and TimeField
919          */
920         ,
921         validate: function() {
922                 return this.df.validate() && this.tf.validate();
923         }
924         // eo function validate
925         // }}}
926         // {{{
927         /**
928          * Returns renderer suitable to render this field
929          * @param {Object} Column model config
930          */
931         ,
932         renderer: function(field) {
933                 var format = field.editor.dateFormat || Gilbert.lib.ui.DateTimeField.prototype.dateFormat;
934                 format += ' ' + (field.editor.timeFormat || Gilbert.lib.ui.DateTimeField.prototype.timeFormat);
935                 var renderer = function(val) {
936                         var retval = Ext.util.Format.date(val, format);
937                         return retval;
938                 };
939                 return renderer;
940         }
941         // eo function renderer
942         // }}}
943 });
944 // eo extend
945 // register xtype
946 Ext.reg('gilbertdatetimefield', Gilbert.lib.ui.DateTimeField);