@atlaskit/editor-core
Version:
A package contains Atlassian editor core functionality
104 lines (95 loc) • 2.69 kB
text/typescript
function getNodeName(node: Node | null | undefined): string | null | undefined {
return node && node.nodeName.toUpperCase();
}
function isMedia (node: Node | null): boolean {
if (!node) {
return false;
}
if (getNodeName(node) === 'SPAN' && node instanceof HTMLElement) {
return !!node.querySelector(
'a > jira-attachment-thumbnail > img[data-attachment-type="thumbnail"], ' +
'a[data-attachment-type="file"]'
);
}
return false;
}
function repairParagraph (p: HTMLParagraphElement) {
const paragraphs: Array<Array<Node>> = [];
let buffer: Array<Node> = [];
let mediaGroupFound = false;
let skipBuffer = false;
const processMedia = () => {
if (buffer.length) {
const head = buffer[0];
if (getNodeName(head) === 'BR') {
buffer.shift();
}
paragraphs.push(buffer);
buffer = [];
}
};
for (let i = 0, length = p.childNodes.length; i < length; i++) {
const node = p.childNodes[i];
skipBuffer = false;
// [..., M, BR, ...]
if (getNodeName(node) === 'BR') {
// [mmm, M, BR, ...]
if (mediaGroupFound) {
processMedia();
mediaGroupFound = false;
skipBuffer = true;
}
// [..., BR, M, ...]
if (isMedia(node.nextSibling)) {
mediaGroupFound = true;
if (buffer.length) {
paragraphs.push(buffer);
buffer = [];
}
}
}
else if (isMedia(node)) {
// [M, ...]
if (node.previousSibling === null) {
mediaGroupFound = true;
}
} else {
if (mediaGroupFound) {
// Skip white space characters inside media
if (getNodeName(node) === '#TEXT' && (node.textContent || '').trim() === '') {
continue;
}
buffer = (paragraphs.pop() || []).concat(buffer);
mediaGroupFound = false;
}
}
if (!skipBuffer) {
buffer.push(node);
}
}
if (mediaGroupFound) {
processMedia();
} else {
paragraphs.push(buffer);
}
if (paragraphs.length > 1) {
const fragment = document.createDocumentFragment();
paragraphs.forEach(childP => {
const innerP = document.createElement('p');
childP.forEach(child => innerP.appendChild(child));
fragment.appendChild(innerP);
});
// Replace old P
const parent = p.parentNode!;
parent.insertBefore(fragment, p.nextSibling);
// IE11 doesn't support remove
parent.removeChild(p);
}
}
export default function (doc: Document): Document {
const paragraphs = doc.querySelectorAll('p');
for (let i = 0, length = paragraphs.length; i < length; i++) {
repairParagraph(paragraphs[i]);
}
return doc;
}