apostrophe
Version:
The Apostrophe Content Management System.
98 lines (94 loc) • 2.75 kB
JavaScript
// Detect whether a document or document field has been changed,
// in a way that warrants confirmation before exiting a modal,
// or emitting an update event
// Optionally returns an array of differeing field names
import { isEqual } from 'lodash';
export function detectDocChange(schema, v1, v2, options = {}) {
// Handle null docs
if (!v1) {
// If there is no v1 then it's a change if there is a v2
return !!v2;
}
if (!v2) {
// If there is no v2 then it's a change if there was a v1
return !!v1;
}
if (options.differences) {
const differences = [];
schema.forEach(field => {
if (detectFieldChange(field, v1[field.name], v2[field.name])) {
differences.push(field.name);
}
});
return differences;
} else {
return schema.some(field => {
return detectFieldChange(field, v1[field.name], v2[field.name]);
});
}
}
export function detectFieldChange(field, v1, v2) {
if (field.type === 'relationshipReverse') {
return false;
}
if (field.type === 'relationship') {
v1 = relevantRelationship(v1);
v2 = relevantRelationship(v2);
} else {
v1 = relevant(v1);
v2 = relevant(v2);
}
if (isEqual(v1, v2)) {
return false;
} else if (!v1 && !v2) {
// False values from select,
// radio and boolean fields are
// detected as a change when selected.
if (
(v1 === false && v2 !== false) ||
(v1 !== false && v2 === false)
) {
return true;
}
return false;
} else if (!v1 && Array.isArray(v2) && v2.length === 0) {
return false;
} else {
return true;
}
function relevant(o) {
if ((o != null) && ((typeof o) === 'object')) {
const newObject = {};
for (const [ key, val ] of Object.entries(o)) {
if (key === '_docId') {
newObject._docId = (o._docId == null) ? null : o._docId.replace(/:.*$/, '');
} else if (key === '_id') {
// So draft and published can be compared
newObject._id = o._id.replace(/:[\w-]+:[\w]+$/, '');
} else if (key.substring(0, 1) === '_') {
// Different results for temporary properties
// don't matter, except for relationships
if (Array.isArray(o[key])) {
newObject[key] = relevantRelationship(o[key]);
} else {
continue;
}
} else {
newObject[key] = relevant(val);
}
}
return newObject;
}
return o;
}
function relevantRelationship(a) {
if (!Array.isArray(a)) {
return [];
}
return a.map(item => ({
// So draft and published can be compared
_id: item._id.replace(/:[\w-]+:[\w]+$/, ''),
_fields: relevant(item._fields)
}));
}
}