alchemymvc
Version:
MVC framework for Node.js
287 lines (233 loc) • 5.58 kB
JavaScript
/**
* Class that holds a value, its field and its full path
*
* @constructor
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 1.1.0
* @version 1.1.0
*
* @param {Field} field The field definition
* @param {string} path The full path to the value (includes indexes)
* @param {*} value
*/
const FieldValue = Function.inherits(null, 'Alchemy', function FieldValue(field, path, value) {
this.field = field;
this.path = path;
this.value = value;
this.translated = false;
this.expanded = false;
});
/**
* Get the translated values, if possible
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 1.1.0
* @version 1.1.4
*
* @return {FieldValue[]}
*/
FieldValue.setMethod(function getTranslatedValues() {
if (this.translated || !this.field.requires_translating) {
return [this];
}
let prefixes = alchemy.getPrefixes(),
result = [],
prefix,
path,
val,
fv;
for (prefix in prefixes) {
if (!this.value) {
val = undefined;
} else {
val = this.value[prefix];
}
path = this.path + '.' + prefix;
fv = new FieldValue(this.field, path, val);
fv.translated = true;
result.push(fv);
}
return result;
});
/**
* Get the array values, if possible
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 1.1.0
* @version 1.1.0
*
* @return {FieldValue[]}
*/
FieldValue.setMethod(function unwind() {
if (this.expanded) {
return [this];
}
let result = this.getTranslatedValues();
if (!this.field.is_array) {
return result;
}
let start = result.slice(0),
path,
temp,
val,
fv,
i,
j;
// Clear out the current field values,
// the array entries will be added here
result = [];
// Iterate over all the expanded translations
// (If there were no translations, this will be an array with `this` only)
for (i = 0; i < start.length; i++) {
fv = start[i];
if (!fv.value || !Array.isArray(fv.value)) {
fv.expanded = true;
result.push(fv);
continue;
}
// When the array is empty, create a dummy entry with an undefined value
// But use the original path (or else error reporting would be weird)
// Also do not use the empty array as a value (because string validation could get weird)
// This is not an ideal situation, but it works
if (!fv.value.length) {
temp = new FieldValue(fv.field, fv.path);
temp.expanded = true;
result.push(temp);
continue;
}
for (j = 0; j < fv.value.length; j++) {
val = fv.value[j];
path = fv.path + '.' + j;
temp = new FieldValue(fv.field, path, val);
temp.translated = fv.translated;
temp.expanded = true;
result.push(temp);
}
}
return result;
});
/**
* Refine the values
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 1.1.0
* @version 1.1.0
*
* @param {Field[]} A chain of fields
*
* @return {FieldValue[]}
*/
FieldValue.setMethod(function refine(fields) {
let result = this.unwind();
// If there is nothing to refine, return ourselves in an array
if (!fields || !fields.length) {
return result;
}
let field,
temp,
i,
j;
for (i = 0; i < fields.length; i++) {
field = fields[i];
temp = [];
for (j = 0; j < result.length; j++) {
temp.include(result[j].getSubfieldValues(field));
}
result = temp;
}
return result;
});
/**
* Get subfield values
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 1.1.0
* @version 1.1.0
*
* @param {Field[]}
*
* @return {FieldValue[]}
*/
FieldValue.setMethod(function getSubfieldValues(field) {
if (!this.value) {
return [];
}
let result = [],
path,
temp,
fvs = [this],
val,
fv,
i;
if (this.field.is_translatable && !this.translated) {
let prefixes = alchemy.getPrefixes(),
prefix,
start = fvs.slice(0),
j;
// Clear out the current field values,
// the translatable entries will be added here
fvs = [];
// Iterate over all the expanded translations
// (This will always be only 1 entry in case of translations)
for (i = 0; i < start.length; i++) {
fv = start[i];
if (!fv.value || typeof fv.value != 'object') {
continue;
}
for (prefix in prefixes) {
val = fv.value[prefix];
if (!val) {
continue;
}
path = fv.path + '.' + prefix;
temp = new FieldValue(fv.field, path, val);
fvs.push(temp);
}
}
}
if (this.field.is_array) {
let start = fvs.slice(0),
j;
// Clear out the current field values,
// the array entries will be added here
fvs = [];
// Iterate over all the expanded translations
// (If there were no translations, this will be an array with `this` only)
for (i = 0; i < start.length; i++) {
fv = start[i];
// Has this already been expanded?
if (fv.expanded) {
fvs.push(fv);
continue;
}
if (!fv.value || !Array.isArray(fv.value)) {
continue;
}
for (j = 0; j < fv.value.length; j++) {
val = fv.value[j];
if (!val) {
continue;
}
path = fv.path + '.' + j;
temp = new FieldValue(fv.field, path, val);
fvs.push(temp);
}
}
}
for (i = 0; i < fvs.length; i++) {
fv = fvs[i];
// If the value is falsy, no sub-values exist
// and it should be ignored
if (!fv.value) {
continue;
}
val = fv.value[field.name];
path = fv.path + '.' + field.name;
// Create a new FieldValue instance
// (In this case: we WANT empty values)
temp = new FieldValue(field, path, val);
result.push(temp);
}
return result;
});