mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-07-28 17:02:04 +03:00
Improved anchor updating/remove action
Now will update the link mark if you have a no-range selection on the link.
This commit is contained in:
@ -6,6 +6,7 @@ import schema from "../schema";
|
|||||||
|
|
||||||
import {MenuItem} from "./menu";
|
import {MenuItem} from "./menu";
|
||||||
import {icons} from "./icons";
|
import {icons} from "./icons";
|
||||||
|
import {markRangeAtPosition, nullifyEmptyValues} from "../util";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {PmMarkType} markType
|
* @param {PmMarkType} markType
|
||||||
@ -69,17 +70,29 @@ function getLinkDialog(submitter, closer) {
|
|||||||
*/
|
*/
|
||||||
function applyLink(formData, state, dispatch) {
|
function applyLink(formData, state, dispatch) {
|
||||||
const selection = state.selection;
|
const selection = state.selection;
|
||||||
const attrs = Object.fromEntries(formData);
|
const attrs = nullifyEmptyValues(Object.fromEntries(formData));
|
||||||
if (dispatch) {
|
if (!dispatch) return true;
|
||||||
|
|
||||||
const tr = state.tr;
|
const tr = state.tr;
|
||||||
|
const noRange = (selection.from - selection.to === 0);
|
||||||
|
let from = selection.from;
|
||||||
|
let to = selection.to;
|
||||||
|
|
||||||
|
if (noRange) {
|
||||||
|
const linkRange = markRangeAtPosition(state, schema.marks.link, selection.from);
|
||||||
|
if (linkRange.from !== -1) {
|
||||||
|
from = linkRange.from;
|
||||||
|
to = linkRange.to;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (attrs.href) {
|
if (attrs.href) {
|
||||||
tr.addMark(selection.from, selection.to, schema.marks.link.create(attrs));
|
tr.addMark(from, to, schema.marks.link.create(attrs));
|
||||||
} else {
|
} else {
|
||||||
tr.removeMark(selection.from, selection.to, schema.marks.link);
|
tr.removeMark(from, to, schema.marks.link);
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(tr);
|
dispatch(tr);
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,49 @@ export function stateToHtml(state) {
|
|||||||
return renderDoc.body.innerHTML;
|
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 {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
|
* @class KeyedMultiStack
|
||||||
* Holds many stacks, seperated via a key, with a simple
|
* Holds many stacks, seperated via a key, with a simple
|
||||||
|
Reference in New Issue
Block a user