PDA

View Full Version : Poor man's DateField



corvonero
14 Sep 2010, 2:26 PM
For those who need and care,
ladies and gentlemen... the DateField ... (sort of!)

Sorry for the quick and dirty code...
I just needed to make it work asap!

Have fun and use at own risk!




/**
* @class Ext.form.Field
* @extends Ext.Container
* <p>Base class for form fields that provides default event handling, sizing, value handling and other functionality. Ext.form.Field
* is not used directly in applications, instead the subclasses such as {@link Ext.form.TextField} should be used.</p>
* @constructor
* Creates a new Field
* @param {Object} config Configuration options
* @xtype field
*/
Ext.form.DateField = Ext.extend(Ext.Component, {
ui: 'text',
isField: true,
baseCls : 'x-field',

/**
* @cfg {String} inputCls Optional CSS class that will be added to the actual <input> element (or whichever different element is
* defined by {@link inputAutoEl}). Defaults to undefined.
*/
inputCls: undefined,

/**
* @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to 'x-field-focus')
*/
focusClass : 'x-field-focus',

/**
* @cfg {Integer} maxLength The maximum number of permitted input characters (defaults to 0).
*/
maxLength : 0,

/**
* @cfg {String} placeHolder A string value displayed in the input (if supported) when the control is empty.
*/
placeHolder : undefined,

/**
* True to set the field's DOM element autocomplete attribute to "on", false to set to "off". Defaults to undefined, leaving the attribute unset
* @cfg {Boolean} autoComplete
*/
autoComplete: undefined,

/**
* True to set the field's DOM element autocapitalize attribute to "on", false to set to "off". Defaults to undefined, leaving the attribute unset
* @cfg {Boolean} autoCapitalize
*/
autoCapitalize: undefined,

/**
* True to set the field's DOM element autofocus attribute to "on", false to set to "off". Defaults to undefined, leaving the attribute unset
* @cfg {Boolean} autoFocus
*/
autoFocus: undefined,

/**
* True to set the field DOM element autocorrect attribute to "on", false to set to "off". Defaults to undefined, leaving the attribute unset.
* @cfg {Boolean} autoCorrect
*/
autoCorrect: undefined,

renderTpl: [
'<tpl if="label"><label <tpl if="fieldEl">for="{inputId}"</tpl>><span>{label}</span></label></tpl>',
'<tpl if="fieldEl"><div id="fakedatefield-{name}" class="fakeFieldContainer"><input id="{inputId}" type="{type}" name="{name}" class="{fieldCls}" ',
'<tpl if="tabIndex">tabIndex="{tabIndex}" </tpl>',
'<tpl if="placeHolder">placeholder="{placeHolder}" </tpl>',
'<tpl if="style">style="{style}" </tpl>',
'<tpl if="maxlength">maxlength="{maxlength}" </tpl>',
'<tpl if="autoComplete">autocomplete="{autoComplete}" </tpl>',
'<tpl if="autoCapitalize">autocapitalize="{autoCapitalize}" </tpl>',
'<tpl if="autoCorrect">autocorrect="{autoCorrect}" </tpl>',
'<tpl if="autoFocus">autofocus="{autoFocus}" </tpl>',
'/></div></tpl>',
'<tpl if="showClear"><div class="x-field-clear x-hidden-display"></div></tpl>',
'<tpl if="maskField"><div class="x-field-mask"></div></tpl>'
],

/**
* @cfg {Boolean} disabled True to disable the field (defaults to false).
* <p>Be aware that conformant with the <a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.12.1">HTML specification</a>,
* disabled Fields will not be {@link Ext.form.BasicForm#submit submitted}.</p>
*/
disabled : false,

// @private
isFormField : true,

/**
* @cfg {Boolean} hasFocus <tt>True</tt> to set input focus immediately after rendered.
*
* @property {Boolean} <tt>True</tt> if the field currently has focus.
*/
hasFocus : false,

/**
* @cfg {Boolean} autoCreateField True to automatically create the field input element on render. This is true by default, but should
* be set to false for any Ext.Field subclasses that don't need an HTML input (e.g. Ext.Slider and similar)
*/
autoCreateField: true,

/**
* @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password, file (defaults
* to 'text'). The types 'file' and 'password' must be used to render those field types currently -- there are
* no separate Ext components for those. Note that if you use <tt>type:'file'</tt>, {@link #emptyText}
* is not supported and should be avoided.
*/
inputType: 'hidden',

/**
* @cfg {String} label The label to associate with this field. Defaults to <tt>null</tt>.
*/
label: null,

labelWidth: 100, // Currently unsupported

/**
* @cfg {String} labelAlign The location to render the label of the field. Acceptable values are 'top' and 'left', defaults to 'left'
*/
labelAlign: 'left',

/**
* @cfg {Boolean} required True to make this field required. Note: this only causes a visual indication. Doesn't prevent user from submitting the form.
*/
required: false,

maskField: false,

// @private
initComponent : function() {
//backwards compatibility - deprecate in next major release
this.label = this.label || this.fieldLabel;

Ext.form.DateField.superclass.initComponent.call(this);
this.addEvents(
/**
* @event focus
* Fires when this field receives input focus.
* @param {Ext.form.Field} this
*/
'focus',
/**
* @event blur
* Fires when this field loses input focus.
* @param {Ext.form.Field} this
*/
'blur',
/**
* @event change
* Fires just before the field blurs if the field value has changed.
* @param {Ext.form.Field} this
* @param {Mixed} newValue The new value
* @param {Mixed} oldValue The original value
*/
'change',
/**
* @event keyup
* Fires when a key is released on the input element.
* @param {Ext.form.Field} this
* @param {Ext.EventObject} e
*/
'keyup'
);
},

/**
* Returns the {@link Ext.form.Field#name name} or {@link Ext.form.ComboBox#hiddenName hiddenName}
* attribute of the field if available.
* @return {String} name The field {@link Ext.form.Field#name name} or {@link Ext.form.ComboBox#hiddenName hiddenName}
*/
getName : function() {
return this.name || this.id || '';
},

/**
* @private
*/
applyRenderSelectors: function() {
this.renderSelectors = Ext.applyIf(this.renderSelectors || {}, {
mask : '.x-field-mask',
labelEl: 'label',
clearEl: '.x-field-clear',
fieldEl: '.' + this.renderData.fieldCls.trim().replace(/ /g, '.')
});
Ext.form.DateField.superclass.applyRenderSelectors.call(this);
},

initRenderData: function() {
var me = this,
renderData = Ext.form.DateField.superclass.initRenderData.call(this),
autoComplete = me.autoComplete,
autoCapitalize = me.autoCapitalize,
autoFocus = me.autoFocus,
autoCorrect = me.autoCorrect;

Ext.applyIf(renderData, {
disabled: me.disabled,
fieldCls: 'x-input-' + me.inputType + (me.inputCls ? ' ' + me.inputCls : ''),
fieldEl: !me.fieldEl && me.autoCreateField,
inputId: Ext.id(),
label: me.label,
labelAlign: 'x-label-align-' + me.labelAlign,
name: me.name || me.id,
placeHolder: me.placeHolder,
required: me.required,
style: me.style,
tabIndex: me.tabIndex,
maxlength : me.maxLength,
type: me.inputType,
maskField: me.maskField,
showClear: me.showClear
});

var positive = /true|on/i;
if (autoComplete !== undefined) {
renderData.autoComplete = positive.test(autoComplete + '') ? 'on' : 'off';
}

if (autoCapitalize !== undefined) {
renderData.autoCapitalize = positive.test(autoCapitalize + '') ? 'on' : 'off';
}

if (autoCorrect !== undefined) {
renderData.autoCorrect = positive.test(autoCorrect + '') ? 'on' : 'off';
}

if (autoFocus !== undefined) {
renderData.autoFocus = positive.test(autoFocus + '') ? 'on' : 'off';
me.autoFocus = renderData.autoFocus == 'on';
}

this.renderData = renderData;
return renderData;
},

onRender : function() {
Ext.form.DateField.superclass.onRender.apply(this, arguments);

var cls = [];
if (this.required) {
cls.push('x-field-required');
}
if (this.label) {
cls.push('x-label-align-' + this.labelAlign);
}
this.el.addClass(cls);

console.log("THIS COMPONENT",this);
this.fakeContainer = new Ext.Panel({
bodyBorder: 0,
cls: 'whitebackground',
layout: 'hbox',
//html: this.value.format(this.dateFormat),
renderTo: "fakedatefield-"+this.name,
height: 38
});

this.fakeLabel = new Ext.Panel({
cls: 'whitebackground',
bodyBorder: 0,
html: this.value.format(this.dateFormat)
});

this.fakeContainer.add(this.fakeLabel);
this.changeButton = new Ext.Button({
width: 70,
text: 'Change'
});

spacer = new Ext.Spacer({
width: 10
});

this.fakeContainer.add(spacer);

this.fakeContainer.add(this.changeButton);

this.changeButton.setHandler(function() {
console.log("Starting picker");
console.log(this.value);
picker = new Ext.DatePicker({
useTitles: true,
value: {
day: this.value.format('d'),
month: this.value.format('n'),
year: this.value.format('Y')
},
yearFrom: 1900,
yearTo: parseInt(this.value.format('Y'))
});

picker.on('change',function(p,v) {
this.setValue(v);
}, this);

console.log("HERE");
picker.show();
}, this);

this.fakeContainer.doLayout();
},

initEvents : function() {
var me = this;

Ext.form.DateField.superclass.initEvents.call(me);

if (me.fieldEl) {
me.mon(me.fieldEl, {
focus: me.onFocus,
blur: me.onBlur,
keyup: me.onKeyUp,
paste: me.checkClear,
scope: me
});

if (me.maskField) {
me.mon(me.mask, {
tap: me.onMaskTap,
scope: me
});
}

if(me.clearEl){
me.mon(me.clearEl, {
scope: this,
tap: this.onClearTap
});
}
}
},

// @private
onEnable : function() {
this.el.removeClass(this.disabledClass);
this.el.dom.disabled = false;
this.fieldEl.dom.disabled = false;
this.checkClear();
},

// @private
onDisable : function() {
this.el.addClass(this.disabledClass);
this.el.dom.disabled = true;
this.fieldEl.dom.disabled = true;
this.checkClear(true);
},

// @private
initValue : function() {
if (this.value !== undefined) {
this.setValue(this.value);
}

/**
* The original value of the field as configured in the {@link #value} configuration, or
* as loaded by the last form load operation if the form's {@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}
* setting is <code>true</code>.
* @type mixed
* @property originalValue
*/
this.originalValue = this.getValue();
},

/**
* <p>Returns true if the value of this Field has been changed from its original value.
* Will return false if the field is disabled or has not been rendered yet.</p>
* <p>Note that if the owning {@link Ext.form.BasicForm form} was configured with
* {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}
* then the <i>original value</i> is updated when the values are loaded by
* {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#setValues setValues}.</p>
* @return {Boolean} True if this field has been changed from its original value (and
* is not disabled), false otherwise.
*/
isDirty : function() {
if (this.disabled || !this.rendered) {
return false;
}
return String(this.getValue()) !== String(this.originalValue);
},

onClearTap: function(){
this.setValue('');
},

checkClear: function(force){
var clearEl = this.clearEl,
fieldEl = this.fieldEl,
value = this.getValue();
if (!(clearEl && fieldEl)) {
return;
}
value = Ext.isEmpty(value) ? '' : String(value);
if(force || value.length === 0){
clearEl.addClass('x-hidden-display');
fieldEl.removeClass('x-field-clearable');
}else{
clearEl.removeClass('x-hidden-display');
fieldEl.addClass('x-field-clearable');
}

},

// @private
afterRender : function() {
Ext.form.DateField.superclass.afterRender.call(this);
this.initValue();
this.checkClear();
if(this.autoFocus && !('autofocus' in this.fieldEl.dom)) {
this.focus();
}
},

onKeyUp : function(e) {
this.checkClear();
this.fireEvent('keyup', this, e);
},

onMaskTap : function(e) {
this.mask.hide();
},

/**
* Resets the current field value to the originally loaded value and clears any validation messages.
* See {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}
*/
reset : function() {
this.setValue(this.originalValue);
},

// @private
beforeFocus: Ext.emptyFn,

undoNativeScroll : function() {
var parent = this.el.parent();
while (parent) {
if (parent.getStyle('overflow') == 'hidden') {
parent.dom.scrollTop = 0;
parent.dom.scrollLeft = 0;
}
parent = parent.parent();
}
},

// @private
onFocus : function(e) {

var me = this;
setTimeout(function() {
me.undoNativeScroll();
}, 0);

this.beforeFocus();
if (this.focusClass) {
this.el.addClass(this.focusClass);
}

if (!this.hasFocus) {
this.hasFocus = true;
/**
* <p>The value that the Field had at the time it was last focused. This is the value that is passed
* to the {@link #change} event which is fired if the value has been changed when the Field is blurred.</p>
* <p><b>This will be undefined until the Field has been visited.</b> Compare {@link #originalValue}.</p>
* @type mixed
* @property startValue
*/
this.startValue = this.getValue();
this.fireEvent('focus', this);
}
},

// @private
beforeBlur : Ext.emptyFn,

// @private
onBlur : function() {
this.beforeBlur();
if (this.focusClass) {
this.el.removeClass(this.focusClass);
}
this.hasFocus = false;
var v = this.getValue();
if (String(v) != String(this.startValue)){
this.fireEvent('change', this, v, this.startValue);
}
this.fireEvent('blur', this);
this.checkClear();
if (this.maskField) {
this.mask.show();
}
this.postBlur();
},

// @private
postBlur : Ext.emptyFn,

/**
* Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
* @return {Mixed} value The field value
*/
getValue : function(){
if (!this.rendered || !this.fieldEl) {
return this.value;
}
return this.fieldEl.getValue();
},


/**
* Attempts to set the field as the active input focus.
* @return {Ext.form.Field} this
*/
focus : function(){
if(this.rendered && this.fieldEl && this.fieldEl.dom.focus) {
this.fieldEl.dom.focus();
}
return this;
},

/**
* Attempts to forcefully blur input focus for the field.
* @return {Ext.form.Field} this
*/
blur : function(){
if(this.rendered && this.fieldEl && this.fieldEl.dom.blur) {
this.fieldEl.dom.blur();
}
return this;
},

/**
* Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
* @param {Mixed} value The value to set
* @return {Ext.form.Field} this
*/
setValue : function(v){
if (!Ext.isDate(v)) {
v = new Date();
}
this.value = v;
if (this.rendered && this.fieldEl) {
this.fieldEl.dom.value = (Ext.isEmpty(v) ? '' : v);
}
this.checkClear();
this.fakeLabel.update(v.format(this.dateFormat));
return this;
}
});

Ext.reg('datefield', Ext.form.DateField);




You will also need some css hack..
I have used the following...
but I am more than sure it will not fit anyone's needs!

.whitebackground div.x-panel-body {
background: transparent !important;
}

div.fakeFieldContainer {

-webkit-appearance: none;
-webkit-box-sizing: border-box;
-webkit-rtl-ordering: logical;
-webkit-user-select: text;
background-attachment: scroll;
background-clip: border-box;
background-color: white;
background-image: none;
background-origin: padding-box;
border-bottom-color: #DED9D4;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
border-bottom-style: solid;
border-bottom-width: 0px;
border-left-style: none;
border-left-width: 0px;
border-right-style: none;
border-right-width: 0px;
border-top-left-radius: 0px;
border-top-right-radius: 0px;
border-top-style: none;
border-top-width: 0px;
color: black;
cursor: auto;
display: block;
font-family: 'Helvetica Neue', HelveticaNeue, Helvetica-Neue, Helvetica, sans-serif;
font-size: 16px;
font-style: normal;
font-variant: normal;
font-weight: normal;
letter-spacing: normal;
line-height: normal;
margin-bottom: 0px;
margin-left: 0px;
margin-right: 0px;
margin-top: 0px;
padding-bottom: 4px;
padding-left: 169px;
padding-right: 4px;
padding-top: 4px;
text-align: auto;
text-indent: 0px;
text-shadow: none;
text-transform: none;
width: 1640px;
word-spacing: 0px;

}


Example usage:



{
xtype: 'datefield',
name : 'mydate',
label: 'Data di nascita',
dateFormat: 'd/m/Y',
value: new Date(),
yearFrom: 1910,
yearTo: new Date('Y')
}

corvonero
15 Sep 2010, 1:36 PM
Please,
pay attention...
this component does not work 100%...

will post a new versio asap.
c.

rdougan
15 Sep 2010, 4:28 PM
There will be a new component called Date Picker Field in the next release (.96) of Sencha Touch which will replicate this. :)

corvonero
21 Sep 2010, 5:24 PM
I really hope it will fix and replicate this ;)
This is SOOO buggy...
sending a new one asap

corvonero
21 Sep 2010, 6:26 PM
Poor man date field, rivised.




Ext.ns('Ext.ux.form');
Ext.ux.form.DateField = Ext.extend(Ext.form.Select, {

value: new Date(),
dateFormat: 'd/m/Y',
yearFrom: 1900,
yearTo: parseInt(new Date().format('Y')),
ui: 'select',
valueField: 'value',
displayField: 'text',
maskField: true,
prependText: '',
initComponent : function() {
this.label = this.label || this.fieldLabel;
var options = this.options,
parsedData = [],
ln = options && options.length,
i, item, obj;


this.tabIndex = -1;

Ext.ux.form.DateField.superclass.initComponent.call(this);

this.addEvents(
'change'
);

},

onMaskTap : function() {
if (1) {

if (!Ext.isDate(this.value)) {
d = new Date();
} else {
d = this.value;
}
this.picker = new Ext.DatePicker({
hideOnMaskTap: true,
useTitles: true,
value: {
day: parseInt(d.format('d')),
month: parseInt(d.format('n')),
year: parseInt(d.format('Y'))
},
yearFrom: parseInt(this.yearFrom),
yearTo: parseInt(this.yearTo),
listeners: {
change: this.onPickerChange,
hide: this.onPickerHide,
scope: this
}

});

this.picker.show();
}

},

onPickerChange : function(picker, value) {
this.setValue(value);
this.fireEvent('change', this, this.getValue());
},

setValue : function(v) {
if (!Ext.isDate(v)) {
this.value = null;
this.fieldEl.dom.value = this.prependText + ' ';
} else {

this.value = v;
if (this.rendered) {
this.fieldEl.dom.value = this.prependText + ' ' + this.value.format(this.dateFormat);
}

else {
this.value = v;
}

}

return this;
}
});

Ext.reg('pmdatefield', Ext.ux.form.DateField);



Usage:




datadinascitaform = new Ext.ux.form.DateField({
name: 'datadinascita',
value: Date.parseDate(dateFromServer,'c'),
label: 'Data di nascita',
dateFormat: 'd/m/Y'
});

tomalex0
21 Sep 2010, 11:17 PM
Hi Thanks for the extension, its working fine