/* Copyright (c) 2010, Sage Software, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @class argos.Fields._Field
* @classdesc Field is the base class for all field controls. It describes all the functions a field should support giving no implementation itself, merely a shell. The one function that `_Field` does provide that most fields leave untouched is `validate`.
* All fields are dijit Widgets meaning it goes through the same lifecycle and has all the Widget functionality.
* @mixins argos._ActionMixin
* @mixins argos._Templated
* @requires argos.FieldManager
*/
import declare from 'dojo/_base/declare';
import lang from 'dojo/_base/lang';
import string from 'dojo/string';
import _WidgetBase from 'dijit/_WidgetBase';
import _ActionMixin from '../_ActionMixin';
import _Templated from '../_Templated';
const __class = declare('argos.Fields._Field', [_WidgetBase, _ActionMixin, _Templated], /** @lends argos.Fields._Field# */ {
/**
* @property {View}
* View that controls the field.
*/
owner: false,
/**
* @property {String}
* If defined it will use the applyTo string when getting and setting properties from
* the SData object instead of the `property` property.
*/
applyTo: false,
/**
* @property {Boolean}
* Signifies that the field should always be included when the form calls {@link Edit#getValues getValues}.
*/
alwaysUseValue: false,
/**
* @property {Boolean}
* Indicates the disabled state
*/
disabled: false,
/**
* @property {Boolean}
* Indicates the visibility state
*/
hidden: false,
/**
* This applies a default value when inserting a new record, the default value
* is applied after the template entry but before the context and changes are applied.
*
* Note the word `default` must be in quotes as default is a reserved word in javascript.
*/
default: undefined,
/**
* @property {String}
* The unique (within the current form) name of the field
*/
name: null,
/**
* @property {String}
* The text that will, by default, show to the left of a field.
*/
label: null,
/**
* @property {String}
* The SData property that the field will be bound to.
*/
property: null,
/**
* @property {String}
* The registered name of the field that gets mapped in {@link FieldManager FieldManager} when
* the field is constructed
*/
type: null,
/**
* @property {Boolean}
* Flag to indicate if this field should be focused when the form is shown.
*/
autoFocus: false,
app: null,
reui: null,
highlightCls: 'field-highlight',
/**
* @property {Simplate}
* Simplate used to define the fields HTML Markup
*/
widgetTemplate: new Simplate([
'<input data-dojo-attach-point="inputNode">',
]),
/**
* @property {HTMLElement}
* The parent container element of the field.
*/
containerNode: null,
/**
* Passed options object will be mixed into the field, overwriting any defaults.
* @param {Object} o Override options
* @constructs
*/
constructor: function constructor(o) {
lang.mixin(this, o);
if (this.app === null) {
this.app = window.App;
}
if (this.reui === null) {
this.reui = window.ReUI;
}
},
/**
* Focuses the input for the field
*/
focus: function focus() {},
/**
* Inserts the field into the given DOM node using dijit Widget `placeAt(node)` and saves
* a reference to it to `this.containerNode`.
* @param {HTMLElement} node Target node to insert the field into
*/
renderTo: function renderTo(node) {
this.containerNode = node; // todo: should node actually be containerNode instead of last rendered node?
this.placeAt(node);
},
/**
* Calledd during app startup after all fields have been inserted into the view
* @template
*/
init: function init() {},
/**
* Determines if the fields' value has changed from the original value. Each field type
* should override this function and provide one tailored to its datatype.
* @template
* @return {Boolean} True if the value has been modified (dirty).
*/
isDirty: function isDirty() {
return true;
},
/**
* Sets disabled to false and fires {@link #onEnable onEnable}.
*/
enable: function enable() {
this.disabled = false;
this.onEnable(this);
},
/**
* Sets disabled to true and fires {@link #onDisable onDisable}.
*/
disable: function disable() {
this.disabled = true;
this.onDisable(this);
},
/**
* Returns the disabled state
* @return {Boolean}
*/
isDisabled: function isDisabled() {
return this.disabled;
},
/**
* Sets hidden to false and fires {@link #onShow onShow}.
*/
show: function show() {
this.hidden = false;
this.onShow(this);
},
/**
* Sets hidden to true and fires {@link #onHide onHide}.
*/
hide: function hide() {
this.hidden = true;
this.onHide(this);
},
/**
* Returns the hidden state
* @return {Boolean}
*/
isHidden: function isHidden() {
return this.hidden;
},
/**
* Each field type will need to implement this function to return the value of the field.
* @template
*/
getValue: function getValue() {},
/**
* Each field type will need to implement this function to set the value and represent the change visually.
* @param {String/Boolean/Number/Object} val The value to set
* @param {Boolean} initial If true the value is meant to be the default/original/clean value.
* @template
*/
setValue: function setValue(/* val, initial*/) {},
/**
* Each field type will need to implement this function to clear the value and visually.
* @template
*/
clearValue: function clearValue() {},
/**
* The validate function determines if there is any errors - meaning it will return false for a "Error free" field.
*
* ###Basic Flow:
*
* * loops over each `validator` defined on the field
*
* * Evaluate the result
* * If the validator is a RegExp, use return `!regExp.test(value)`
* * If the validator is a function, call and return the result of the function passing the value, _Field instance, and the `owner` property.
* * If the validator is an object and has a `test` key, follow the RegExp path.
* * If the validator is an object and has a `fn` key, follow the function path.
*
* * If the result is true and the validator is an object with a `message` key:
* * If message is a function, call and return the result of the function passing the value, _Field instance and the `owner` property.
* * Otherwise, assume it is a string format and call dojo's `string.substitute` using the message as the format, `${0}` as the value, `${1}` as the fields name, `${2}` as the fields label property.
* * Save the result of the function or string substitution as the result itself.
*
* * Return the result.
* @param value Value of the field, if not passed then {@link #getValue getValue} is used.
* @return {Boolean/Object} False signifies that everything is okay and the field is valid, `true` or a `string message` indicates that it failed.
*/
validate: function validate(value) {
if (typeof this.validator === 'undefined') {
return false;
}
const all = Array.isArray(this.validator) ? this.validator : [this.validator];
for (let i = 0; i < all.length; i++) {
const current = all[i];
let definition;
if (current instanceof RegExp) {
definition = {
test: current,
};
} else if (typeof current === 'function') {
definition = {
fn: current,
};
} else {
definition = current;
}
const newValue = typeof value === 'undefined' ? this.getValue() : value;
let result = false;
if (typeof definition.fn === 'function') {
result = definition.fn.call(definition.scope || this, newValue, this, this.owner);
} else if (definition.test instanceof RegExp) {
result = !definition.test.test(newValue);
}
if (result) {
if (definition.message) {
result = typeof definition.message === 'function' ? definition.message.call(definition.scope || this, newValue, this, this.owner) : string.substitute(definition.message, [newValue, this.name, this.label]);
}
return result;
}
}
return false;
},
/**
* Event that fires when the field is enabled
* @param {_Field} field The field itself
* @template
*/
onEnable: function onEnable(/* field*/) {},
/**
* Event that fires when the field is disabled
* @param {_Field} field The field itself
* @template
*/
onDisable: function onDisable(/* field*/) {},
/**
* Event that fires when the field is shown
* @param {_Field} field The field itself
* @template
*/
onShow: function onShow(/* field*/) {},
/**
* Event that fires when the field is hidden
* @param {_Field} field The field itself
* @template
*/
onHide: function onHide(/* field*/) {},
/**
* Event that fires when the field is changed
* @param {_Field} field The field itself
* @template
*/
onChange: function onChange(/* value, field*/) {},
});
export default __class;