@wordpress/core-data
Version:
Access to and manipulation of core WordPress entities.
111 lines (107 loc) • 3.42 kB
JavaScript
/**
* WordPress dependencies
*/
import { RichTextData, create, toHTMLString } from '@wordpress/rich-text';
/**
* Internal dependencies
*/
import getFootnotesOrder from './get-footnotes-order';
let oldFootnotes = {};
export function updateFootnotesFromMeta(blocks, meta) {
const output = {
blocks
};
if (!meta) {
return output;
}
// If meta.footnotes is empty, it means the meta is not registered.
if (meta.footnotes === undefined) {
return output;
}
const newOrder = getFootnotesOrder(blocks);
const footnotes = meta.footnotes ? JSON.parse(meta.footnotes) : [];
const currentOrder = footnotes.map(fn => fn.id);
if (currentOrder.join('') === newOrder.join('')) {
return output;
}
const newFootnotes = newOrder.map(fnId => footnotes.find(fn => fn.id === fnId) || oldFootnotes[fnId] || {
id: fnId,
content: ''
});
function updateAttributes(attributes) {
// Only attempt to update attributes, if attributes is an object.
if (!attributes || Array.isArray(attributes) || typeof attributes !== 'object') {
return attributes;
}
attributes = {
...attributes
};
for (const key in attributes) {
const value = attributes[key];
if (Array.isArray(value)) {
attributes[key] = value.map(updateAttributes);
continue;
}
// To do, remove support for string values?
if (typeof value !== 'string' && !(value instanceof RichTextData)) {
continue;
}
const richTextValue = typeof value === 'string' ? RichTextData.fromHTMLString(value) : new RichTextData(value);
let hasFootnotes = false;
richTextValue.replacements.forEach(replacement => {
if (replacement.type === 'core/footnote') {
const id = replacement.attributes['data-fn'];
const index = newOrder.indexOf(id);
// The innerHTML contains the count wrapped in a link.
const countValue = create({
html: replacement.innerHTML
});
countValue.text = String(index + 1);
countValue.formats = Array.from({
length: countValue.text.length
}, () => countValue.formats[0]);
countValue.replacements = Array.from({
length: countValue.text.length
}, () => countValue.replacements[0]);
replacement.innerHTML = toHTMLString({
value: countValue
});
hasFootnotes = true;
}
});
if (hasFootnotes) {
attributes[key] = typeof value === 'string' ? richTextValue.toHTMLString() : richTextValue;
}
}
return attributes;
}
function updateBlocksAttributes(__blocks) {
return __blocks.map(block => {
return {
...block,
attributes: updateAttributes(block.attributes),
innerBlocks: updateBlocksAttributes(block.innerBlocks)
};
});
}
// We need to go through all block attributes deeply and update the
// footnote anchor numbering (textContent) to match the new order.
const newBlocks = updateBlocksAttributes(blocks);
oldFootnotes = {
...oldFootnotes,
...footnotes.reduce((acc, fn) => {
if (!newOrder.includes(fn.id)) {
acc[fn.id] = fn;
}
return acc;
}, {})
};
return {
meta: {
...meta,
footnotes: JSON.stringify(newFootnotes)
},
blocks: newBlocks
};
}
//# sourceMappingURL=index.js.map