mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-07-21 09:22:09 +03:00
131 lines
3.4 KiB
JavaScript
131 lines
3.4 KiB
JavaScript
import schema from "./schema";
|
|
import {DOMParser, DOMSerializer} from "prosemirror-model";
|
|
|
|
/**
|
|
* @param {String} html
|
|
* @return {PmNode}
|
|
*/
|
|
export function htmlToDoc(html) {
|
|
const renderDoc = document.implementation.createHTMLDocument();
|
|
renderDoc.body.innerHTML = html;
|
|
return DOMParser.fromSchema(schema).parse(renderDoc.body);
|
|
}
|
|
|
|
/**
|
|
* @param {PmNode} doc
|
|
* @return {string}
|
|
*/
|
|
export function docToHtml(doc) {
|
|
const fragment = DOMSerializer.fromSchema(schema).serializeFragment(doc.content);
|
|
const renderDoc = document.implementation.createHTMLDocument();
|
|
renderDoc.body.appendChild(fragment);
|
|
return renderDoc.body.innerHTML;
|
|
}
|
|
|
|
/**
|
|
* @param {PmEditorState} state
|
|
* @return {String}
|
|
*/
|
|
export function stateToHtml(state) {
|
|
const fragment = DOMSerializer.fromSchema(schema).serializeFragment(state.doc.content);
|
|
const renderDoc = document.implementation.createHTMLDocument();
|
|
renderDoc.body.appendChild(fragment);
|
|
return renderDoc.body.innerHTML;
|
|
}
|
|
|
|
/**
|
|
* @param {Object} object
|
|
* @return {{}}
|
|
*/
|
|
export function nullifyEmptyValues(object) {
|
|
const clean = {};
|
|
for (const [key, value] of Object.entries(object)) {
|
|
clean[key] = (value === "") ? null : value;
|
|
}
|
|
return clean;
|
|
}
|
|
|
|
/**
|
|
* @param {PmEditorState} state
|
|
* @param {PmSelection} selection
|
|
* @param {PmMarkType} markType
|
|
* @return {{from: Number, to: Number}}
|
|
*/
|
|
export function expandSelectionToMark(state, selection, markType) {
|
|
let {from, to} = selection;
|
|
const noRange = (from === to);
|
|
if (noRange) {
|
|
const markRange = markRangeAtPosition(state, markType, from);
|
|
if (markRange.from !== -1) {
|
|
from = markRange.from;
|
|
to = markRange.to;
|
|
}
|
|
}
|
|
return {from, to};
|
|
}
|
|
|
|
/**
|
|
* @param {PmEditorState} state
|
|
* @param {PmMarkType} markType
|
|
* @param {Number} pos
|
|
* @return {{from: Number, to: Number}}
|
|
*/
|
|
export function markRangeAtPosition(state, markType, pos) {
|
|
const $pos = state.doc.resolve(pos);
|
|
|
|
const {parent, parentOffset} = $pos;
|
|
const start = parent.childAfter(parentOffset);
|
|
if (!start.node) return {from: -1, to: -1};
|
|
|
|
const mark = start.node.marks.find((mark) => mark.type === markType);
|
|
if (!mark) return {from: -1, to: -1};
|
|
|
|
let startIndex = $pos.index();
|
|
let startPos = $pos.start() + start.offset;
|
|
let endIndex = startIndex + 1;
|
|
let endPos = startPos + start.node.nodeSize;
|
|
while (startIndex > 0 && mark.isInSet(parent.child(startIndex - 1).marks)) {
|
|
startIndex -= 1;
|
|
startPos -= parent.child(startIndex).nodeSize;
|
|
}
|
|
while (endIndex < parent.childCount && mark.isInSet(parent.child(endIndex).marks)) {
|
|
endPos += parent.child(endIndex).nodeSize;
|
|
endIndex += 1;
|
|
}
|
|
return {from: startPos, to: endPos};
|
|
}
|
|
|
|
/**
|
|
* @class KeyedMultiStack
|
|
* Holds many stacks, seperated via a key, with a simple
|
|
* interface to pop and push values to the stacks.
|
|
*/
|
|
export class KeyedMultiStack {
|
|
|
|
constructor() {
|
|
this.stack = {};
|
|
}
|
|
|
|
/**
|
|
* @param {String} key
|
|
* @return {undefined|*}
|
|
*/
|
|
pop(key) {
|
|
if (Array.isArray(this.stack[key])) {
|
|
return this.stack[key].pop();
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
/**
|
|
* @param {String} key
|
|
* @param {*} value
|
|
*/
|
|
push(key, value) {
|
|
if (this.stack[key] === undefined) {
|
|
this.stack[key] = [];
|
|
}
|
|
|
|
this.stack[key].push(value);
|
|
}
|
|
} |