@tiptap/core 2.0.0-beta.196 → 2.0.0-beta.198
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tiptap-core.cjs.js +703 -671
- package/dist/tiptap-core.cjs.js.map +1 -1
- package/dist/tiptap-core.esm.js +705 -673
- package/dist/tiptap-core.esm.js.map +1 -1
- package/dist/tiptap-core.umd.js +703 -671
- package/dist/tiptap-core.umd.js.map +1 -1
- package/package.json +8 -8
- package/src/commands/setMark.ts +44 -2
- package/src/helpers/getAttributesFromExtensions.ts +1 -1
- package/src/helpers/getTextContentFromNodes.ts +8 -4
package/dist/tiptap-core.umd.js
CHANGED
|
@@ -273,7 +273,7 @@
|
|
|
273
273
|
...defaultAttribute,
|
|
274
274
|
...attribute,
|
|
275
275
|
};
|
|
276
|
-
if (attribute.isRequired && attribute.default === undefined) {
|
|
276
|
+
if ((attribute === null || attribute === void 0 ? void 0 : attribute.isRequired) && (attribute === null || attribute === void 0 ? void 0 : attribute.default) === undefined) {
|
|
277
277
|
delete mergedAttr.default;
|
|
278
278
|
}
|
|
279
279
|
extensionAttributes.push({
|
|
@@ -539,11 +539,13 @@
|
|
|
539
539
|
|
|
540
540
|
const getTextContentFromNodes = ($from, maxMatch = 500) => {
|
|
541
541
|
let textBefore = '';
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
542
|
+
const sliceEndPos = $from.parentOffset;
|
|
543
|
+
$from.parent.nodesBetween(Math.max(0, sliceEndPos - maxMatch), sliceEndPos, (node, pos, parent, index) => {
|
|
544
|
+
var _a, _b;
|
|
545
|
+
const chunk = ((_b = (_a = node.type.spec).toText) === null || _b === void 0 ? void 0 : _b.call(_a, {
|
|
545
546
|
node, pos, parent, index,
|
|
546
|
-
})) ||
|
|
547
|
+
})) || node.textContent || '%leaf%';
|
|
548
|
+
textBefore += chunk.slice(0, Math.max(0, sliceEndPos - pos));
|
|
547
549
|
});
|
|
548
550
|
return textBefore;
|
|
549
551
|
};
|
|
@@ -1930,6 +1932,135 @@
|
|
|
1930
1932
|
return true;
|
|
1931
1933
|
};
|
|
1932
1934
|
|
|
1935
|
+
/**
|
|
1936
|
+
* Returns a new `Transform` based on all steps of the passed transactions.
|
|
1937
|
+
*/
|
|
1938
|
+
function combineTransactionSteps(oldDoc, transactions) {
|
|
1939
|
+
const transform = new prosemirrorTransform.Transform(oldDoc);
|
|
1940
|
+
transactions.forEach(transaction => {
|
|
1941
|
+
transaction.steps.forEach(step => {
|
|
1942
|
+
transform.step(step);
|
|
1943
|
+
});
|
|
1944
|
+
});
|
|
1945
|
+
return transform;
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
function defaultBlockAt(match) {
|
|
1949
|
+
for (let i = 0; i < match.edgeCount; i += 1) {
|
|
1950
|
+
const { type } = match.edge(i);
|
|
1951
|
+
if (type.isTextblock && !type.hasRequiredAttrs()) {
|
|
1952
|
+
return type;
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
return null;
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
function findChildren(node, predicate) {
|
|
1959
|
+
const nodesWithPos = [];
|
|
1960
|
+
node.descendants((child, pos) => {
|
|
1961
|
+
if (predicate(child)) {
|
|
1962
|
+
nodesWithPos.push({
|
|
1963
|
+
node: child,
|
|
1964
|
+
pos,
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
});
|
|
1968
|
+
return nodesWithPos;
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
/**
|
|
1972
|
+
* Same as `findChildren` but searches only within a `range`.
|
|
1973
|
+
*/
|
|
1974
|
+
function findChildrenInRange(node, range, predicate) {
|
|
1975
|
+
const nodesWithPos = [];
|
|
1976
|
+
// if (range.from === range.to) {
|
|
1977
|
+
// const nodeAt = node.nodeAt(range.from)
|
|
1978
|
+
// if (nodeAt) {
|
|
1979
|
+
// nodesWithPos.push({
|
|
1980
|
+
// node: nodeAt,
|
|
1981
|
+
// pos: range.from,
|
|
1982
|
+
// })
|
|
1983
|
+
// }
|
|
1984
|
+
// }
|
|
1985
|
+
node.nodesBetween(range.from, range.to, (child, pos) => {
|
|
1986
|
+
if (predicate(child)) {
|
|
1987
|
+
nodesWithPos.push({
|
|
1988
|
+
node: child,
|
|
1989
|
+
pos,
|
|
1990
|
+
});
|
|
1991
|
+
}
|
|
1992
|
+
});
|
|
1993
|
+
return nodesWithPos;
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
function findParentNodeClosestToPos($pos, predicate) {
|
|
1997
|
+
for (let i = $pos.depth; i > 0; i -= 1) {
|
|
1998
|
+
const node = $pos.node(i);
|
|
1999
|
+
if (predicate(node)) {
|
|
2000
|
+
return {
|
|
2001
|
+
pos: i > 0 ? $pos.before(i) : 0,
|
|
2002
|
+
start: $pos.start(i),
|
|
2003
|
+
depth: i,
|
|
2004
|
+
node,
|
|
2005
|
+
};
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
function findParentNode(predicate) {
|
|
2011
|
+
return (selection) => findParentNodeClosestToPos(selection.$from, predicate);
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
function getHTMLFromFragment(fragment, schema) {
|
|
2015
|
+
const documentFragment = prosemirrorModel.DOMSerializer
|
|
2016
|
+
.fromSchema(schema)
|
|
2017
|
+
.serializeFragment(fragment);
|
|
2018
|
+
const temporaryDocument = document.implementation.createHTMLDocument();
|
|
2019
|
+
const container = temporaryDocument.createElement('div');
|
|
2020
|
+
container.appendChild(documentFragment);
|
|
2021
|
+
return container.innerHTML;
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
function getSchema(extensions) {
|
|
2025
|
+
const resolvedExtensions = ExtensionManager.resolve(extensions);
|
|
2026
|
+
return getSchemaByResolvedExtensions(resolvedExtensions);
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
function generateHTML(doc, extensions) {
|
|
2030
|
+
const schema = getSchema(extensions);
|
|
2031
|
+
const contentNode = prosemirrorModel.Node.fromJSON(schema, doc);
|
|
2032
|
+
return getHTMLFromFragment(contentNode.content, schema);
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
function generateJSON(html, extensions) {
|
|
2036
|
+
const schema = getSchema(extensions);
|
|
2037
|
+
const dom = elementFromString(html);
|
|
2038
|
+
return prosemirrorModel.DOMParser.fromSchema(schema)
|
|
2039
|
+
.parse(dom)
|
|
2040
|
+
.toJSON();
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
function getText(node, options) {
|
|
2044
|
+
const range = {
|
|
2045
|
+
from: 0,
|
|
2046
|
+
to: node.content.size,
|
|
2047
|
+
};
|
|
2048
|
+
return getTextBetween(node, range, options);
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
function generateText(doc, extensions, options) {
|
|
2052
|
+
const { blockSeparator = '\n\n', textSerializers = {}, } = options || {};
|
|
2053
|
+
const schema = getSchema(extensions);
|
|
2054
|
+
const contentNode = prosemirrorModel.Node.fromJSON(schema, doc);
|
|
2055
|
+
return getText(contentNode, {
|
|
2056
|
+
blockSeparator,
|
|
2057
|
+
textSerializers: {
|
|
2058
|
+
...textSerializers,
|
|
2059
|
+
...getTextSerializersFromSchema(schema),
|
|
2060
|
+
},
|
|
2061
|
+
});
|
|
2062
|
+
}
|
|
2063
|
+
|
|
1933
2064
|
function getMarkAttributes(state, typeOrName) {
|
|
1934
2065
|
const type = getMarkType(typeOrName, state.schema);
|
|
1935
2066
|
const { from, to, empty } = state.selection;
|
|
@@ -1952,118 +2083,454 @@
|
|
|
1952
2083
|
return { ...mark.attrs };
|
|
1953
2084
|
}
|
|
1954
2085
|
|
|
1955
|
-
|
|
1956
|
-
const { selection } = tr;
|
|
1957
|
-
const { empty, ranges } = selection;
|
|
1958
|
-
const type = getMarkType(typeOrName, state.schema);
|
|
1959
|
-
if (dispatch) {
|
|
1960
|
-
if (empty) {
|
|
1961
|
-
const oldAttributes = getMarkAttributes(state, type);
|
|
1962
|
-
tr.addStoredMark(type.create({
|
|
1963
|
-
...oldAttributes,
|
|
1964
|
-
...attributes,
|
|
1965
|
-
}));
|
|
1966
|
-
}
|
|
1967
|
-
else {
|
|
1968
|
-
ranges.forEach(range => {
|
|
1969
|
-
const from = range.$from.pos;
|
|
1970
|
-
const to = range.$to.pos;
|
|
1971
|
-
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
1972
|
-
const trimmedFrom = Math.max(pos, from);
|
|
1973
|
-
const trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
1974
|
-
const someHasMark = node.marks.find(mark => mark.type === type);
|
|
1975
|
-
// if there is already a mark of this type
|
|
1976
|
-
// we know that we have to merge its attributes
|
|
1977
|
-
// otherwise we add a fresh new mark
|
|
1978
|
-
if (someHasMark) {
|
|
1979
|
-
node.marks.forEach(mark => {
|
|
1980
|
-
if (type === mark.type) {
|
|
1981
|
-
tr.addMark(trimmedFrom, trimmedTo, type.create({
|
|
1982
|
-
...mark.attrs,
|
|
1983
|
-
...attributes,
|
|
1984
|
-
}));
|
|
1985
|
-
}
|
|
1986
|
-
});
|
|
1987
|
-
}
|
|
1988
|
-
else {
|
|
1989
|
-
tr.addMark(trimmedFrom, trimmedTo, type.create(attributes));
|
|
1990
|
-
}
|
|
1991
|
-
});
|
|
1992
|
-
});
|
|
1993
|
-
}
|
|
1994
|
-
}
|
|
1995
|
-
return true;
|
|
1996
|
-
};
|
|
1997
|
-
|
|
1998
|
-
const setMeta = (key, value) => ({ tr }) => {
|
|
1999
|
-
tr.setMeta(key, value);
|
|
2000
|
-
return true;
|
|
2001
|
-
};
|
|
2002
|
-
|
|
2003
|
-
const setNode = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) => {
|
|
2086
|
+
function getNodeAttributes(state, typeOrName) {
|
|
2004
2087
|
const type = getNodeType(typeOrName, state.schema);
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
}
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
.
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
return true;
|
|
2016
|
-
}
|
|
2017
|
-
return commands.clearNodes();
|
|
2018
|
-
})
|
|
2019
|
-
.command(({ state: updatedState }) => {
|
|
2020
|
-
return prosemirrorCommands.setBlockType(type, attributes)(updatedState, dispatch);
|
|
2021
|
-
})
|
|
2022
|
-
.run();
|
|
2023
|
-
};
|
|
2024
|
-
|
|
2025
|
-
const setNodeSelection = position => ({ tr, dispatch }) => {
|
|
2026
|
-
if (dispatch) {
|
|
2027
|
-
const { doc } = tr;
|
|
2028
|
-
const from = minMax(position, 0, doc.content.size);
|
|
2029
|
-
const selection = prosemirrorState.NodeSelection.create(doc, from);
|
|
2030
|
-
tr.setSelection(selection);
|
|
2088
|
+
const { from, to } = state.selection;
|
|
2089
|
+
const nodes = [];
|
|
2090
|
+
state.doc.nodesBetween(from, to, node => {
|
|
2091
|
+
nodes.push(node);
|
|
2092
|
+
});
|
|
2093
|
+
const node = nodes
|
|
2094
|
+
.reverse()
|
|
2095
|
+
.find(nodeItem => nodeItem.type.name === type.name);
|
|
2096
|
+
if (!node) {
|
|
2097
|
+
return {};
|
|
2031
2098
|
}
|
|
2032
|
-
return
|
|
2033
|
-
}
|
|
2099
|
+
return { ...node.attrs };
|
|
2100
|
+
}
|
|
2034
2101
|
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
const minPos = prosemirrorState.TextSelection.atStart(doc).from;
|
|
2042
|
-
const maxPos = prosemirrorState.TextSelection.atEnd(doc).to;
|
|
2043
|
-
const resolvedFrom = minMax(from, minPos, maxPos);
|
|
2044
|
-
const resolvedEnd = minMax(to, minPos, maxPos);
|
|
2045
|
-
const selection = prosemirrorState.TextSelection.create(doc, resolvedFrom, resolvedEnd);
|
|
2046
|
-
tr.setSelection(selection);
|
|
2102
|
+
function getAttributes(state, typeOrName) {
|
|
2103
|
+
const schemaType = getSchemaTypeNameByName(typeof typeOrName === 'string'
|
|
2104
|
+
? typeOrName
|
|
2105
|
+
: typeOrName.name, state.schema);
|
|
2106
|
+
if (schemaType === 'node') {
|
|
2107
|
+
return getNodeAttributes(state, typeOrName);
|
|
2047
2108
|
}
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
const sinkListItem = typeOrName => ({ state, dispatch }) => {
|
|
2052
|
-
const type = getNodeType(typeOrName, state.schema);
|
|
2053
|
-
return prosemirrorSchemaList.sinkListItem(type)(state, dispatch);
|
|
2054
|
-
};
|
|
2055
|
-
|
|
2056
|
-
function defaultBlockAt(match) {
|
|
2057
|
-
for (let i = 0; i < match.edgeCount; i += 1) {
|
|
2058
|
-
const { type } = match.edge(i);
|
|
2059
|
-
if (type.isTextblock && !type.hasRequiredAttrs()) {
|
|
2060
|
-
return type;
|
|
2061
|
-
}
|
|
2109
|
+
if (schemaType === 'mark') {
|
|
2110
|
+
return getMarkAttributes(state, typeOrName);
|
|
2062
2111
|
}
|
|
2063
|
-
return
|
|
2112
|
+
return {};
|
|
2064
2113
|
}
|
|
2065
2114
|
|
|
2066
|
-
|
|
2115
|
+
/**
|
|
2116
|
+
* Removes duplicated values within an array.
|
|
2117
|
+
* Supports numbers, strings and objects.
|
|
2118
|
+
*/
|
|
2119
|
+
function removeDuplicates(array, by = JSON.stringify) {
|
|
2120
|
+
const seen = {};
|
|
2121
|
+
return array.filter(item => {
|
|
2122
|
+
const key = by(item);
|
|
2123
|
+
return Object.prototype.hasOwnProperty.call(seen, key)
|
|
2124
|
+
? false
|
|
2125
|
+
: (seen[key] = true);
|
|
2126
|
+
});
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
/**
|
|
2130
|
+
* Removes duplicated ranges and ranges that are
|
|
2131
|
+
* fully captured by other ranges.
|
|
2132
|
+
*/
|
|
2133
|
+
function simplifyChangedRanges(changes) {
|
|
2134
|
+
const uniqueChanges = removeDuplicates(changes);
|
|
2135
|
+
return uniqueChanges.length === 1
|
|
2136
|
+
? uniqueChanges
|
|
2137
|
+
: uniqueChanges.filter((change, index) => {
|
|
2138
|
+
const rest = uniqueChanges.filter((_, i) => i !== index);
|
|
2139
|
+
return !rest.some(otherChange => {
|
|
2140
|
+
return change.oldRange.from >= otherChange.oldRange.from
|
|
2141
|
+
&& change.oldRange.to <= otherChange.oldRange.to
|
|
2142
|
+
&& change.newRange.from >= otherChange.newRange.from
|
|
2143
|
+
&& change.newRange.to <= otherChange.newRange.to;
|
|
2144
|
+
});
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
/**
|
|
2148
|
+
* Returns a list of changed ranges
|
|
2149
|
+
* based on the first and last state of all steps.
|
|
2150
|
+
*/
|
|
2151
|
+
function getChangedRanges(transform) {
|
|
2152
|
+
const { mapping, steps } = transform;
|
|
2153
|
+
const changes = [];
|
|
2154
|
+
mapping.maps.forEach((stepMap, index) => {
|
|
2155
|
+
const ranges = [];
|
|
2156
|
+
// This accounts for step changes where no range was actually altered
|
|
2157
|
+
// e.g. when setting a mark, node attribute, etc.
|
|
2158
|
+
// @ts-ignore
|
|
2159
|
+
if (!stepMap.ranges.length) {
|
|
2160
|
+
const { from, to } = steps[index];
|
|
2161
|
+
if (from === undefined || to === undefined) {
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2164
|
+
ranges.push({ from, to });
|
|
2165
|
+
}
|
|
2166
|
+
else {
|
|
2167
|
+
stepMap.forEach((from, to) => {
|
|
2168
|
+
ranges.push({ from, to });
|
|
2169
|
+
});
|
|
2170
|
+
}
|
|
2171
|
+
ranges.forEach(({ from, to }) => {
|
|
2172
|
+
const newStart = mapping.slice(index).map(from, -1);
|
|
2173
|
+
const newEnd = mapping.slice(index).map(to);
|
|
2174
|
+
const oldStart = mapping.invert().map(newStart, -1);
|
|
2175
|
+
const oldEnd = mapping.invert().map(newEnd);
|
|
2176
|
+
changes.push({
|
|
2177
|
+
oldRange: {
|
|
2178
|
+
from: oldStart,
|
|
2179
|
+
to: oldEnd,
|
|
2180
|
+
},
|
|
2181
|
+
newRange: {
|
|
2182
|
+
from: newStart,
|
|
2183
|
+
to: newEnd,
|
|
2184
|
+
},
|
|
2185
|
+
});
|
|
2186
|
+
});
|
|
2187
|
+
});
|
|
2188
|
+
return simplifyChangedRanges(changes);
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
function getDebugJSON(node, startOffset = 0) {
|
|
2192
|
+
const isTopNode = node.type === node.type.schema.topNodeType;
|
|
2193
|
+
const increment = isTopNode ? 0 : 1;
|
|
2194
|
+
const from = startOffset;
|
|
2195
|
+
const to = from + node.nodeSize;
|
|
2196
|
+
const marks = node.marks.map(mark => {
|
|
2197
|
+
const output = {
|
|
2198
|
+
type: mark.type.name,
|
|
2199
|
+
};
|
|
2200
|
+
if (Object.keys(mark.attrs).length) {
|
|
2201
|
+
output.attrs = { ...mark.attrs };
|
|
2202
|
+
}
|
|
2203
|
+
return output;
|
|
2204
|
+
});
|
|
2205
|
+
const attrs = { ...node.attrs };
|
|
2206
|
+
const output = {
|
|
2207
|
+
type: node.type.name,
|
|
2208
|
+
from,
|
|
2209
|
+
to,
|
|
2210
|
+
};
|
|
2211
|
+
if (Object.keys(attrs).length) {
|
|
2212
|
+
output.attrs = attrs;
|
|
2213
|
+
}
|
|
2214
|
+
if (marks.length) {
|
|
2215
|
+
output.marks = marks;
|
|
2216
|
+
}
|
|
2217
|
+
if (node.content.childCount) {
|
|
2218
|
+
output.content = [];
|
|
2219
|
+
node.forEach((child, offset) => {
|
|
2220
|
+
var _a;
|
|
2221
|
+
(_a = output.content) === null || _a === void 0 ? void 0 : _a.push(getDebugJSON(child, startOffset + offset + increment));
|
|
2222
|
+
});
|
|
2223
|
+
}
|
|
2224
|
+
if (node.text) {
|
|
2225
|
+
output.text = node.text;
|
|
2226
|
+
}
|
|
2227
|
+
return output;
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
function getMarksBetween(from, to, doc) {
|
|
2231
|
+
const marks = [];
|
|
2232
|
+
// get all inclusive marks on empty selection
|
|
2233
|
+
if (from === to) {
|
|
2234
|
+
doc
|
|
2235
|
+
.resolve(from)
|
|
2236
|
+
.marks()
|
|
2237
|
+
.forEach(mark => {
|
|
2238
|
+
const $pos = doc.resolve(from - 1);
|
|
2239
|
+
const range = getMarkRange($pos, mark.type);
|
|
2240
|
+
if (!range) {
|
|
2241
|
+
return;
|
|
2242
|
+
}
|
|
2243
|
+
marks.push({
|
|
2244
|
+
mark,
|
|
2245
|
+
...range,
|
|
2246
|
+
});
|
|
2247
|
+
});
|
|
2248
|
+
}
|
|
2249
|
+
else {
|
|
2250
|
+
doc.nodesBetween(from, to, (node, pos) => {
|
|
2251
|
+
marks.push(...node.marks.map(mark => ({
|
|
2252
|
+
from: pos,
|
|
2253
|
+
to: pos + node.nodeSize,
|
|
2254
|
+
mark,
|
|
2255
|
+
})));
|
|
2256
|
+
});
|
|
2257
|
+
}
|
|
2258
|
+
return marks;
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
function isMarkActive(state, typeOrName, attributes = {}) {
|
|
2262
|
+
const { empty, ranges } = state.selection;
|
|
2263
|
+
const type = typeOrName
|
|
2264
|
+
? getMarkType(typeOrName, state.schema)
|
|
2265
|
+
: null;
|
|
2266
|
+
if (empty) {
|
|
2267
|
+
return !!(state.storedMarks || state.selection.$from.marks())
|
|
2268
|
+
.filter(mark => {
|
|
2269
|
+
if (!type) {
|
|
2270
|
+
return true;
|
|
2271
|
+
}
|
|
2272
|
+
return type.name === mark.type.name;
|
|
2273
|
+
})
|
|
2274
|
+
.find(mark => objectIncludes(mark.attrs, attributes, { strict: false }));
|
|
2275
|
+
}
|
|
2276
|
+
let selectionRange = 0;
|
|
2277
|
+
const markRanges = [];
|
|
2278
|
+
ranges.forEach(({ $from, $to }) => {
|
|
2279
|
+
const from = $from.pos;
|
|
2280
|
+
const to = $to.pos;
|
|
2281
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
2282
|
+
if (!node.isText && !node.marks.length) {
|
|
2283
|
+
return;
|
|
2284
|
+
}
|
|
2285
|
+
const relativeFrom = Math.max(from, pos);
|
|
2286
|
+
const relativeTo = Math.min(to, pos + node.nodeSize);
|
|
2287
|
+
const range = relativeTo - relativeFrom;
|
|
2288
|
+
selectionRange += range;
|
|
2289
|
+
markRanges.push(...node.marks.map(mark => ({
|
|
2290
|
+
mark,
|
|
2291
|
+
from: relativeFrom,
|
|
2292
|
+
to: relativeTo,
|
|
2293
|
+
})));
|
|
2294
|
+
});
|
|
2295
|
+
});
|
|
2296
|
+
if (selectionRange === 0) {
|
|
2297
|
+
return false;
|
|
2298
|
+
}
|
|
2299
|
+
// calculate range of matched mark
|
|
2300
|
+
const matchedRange = markRanges
|
|
2301
|
+
.filter(markRange => {
|
|
2302
|
+
if (!type) {
|
|
2303
|
+
return true;
|
|
2304
|
+
}
|
|
2305
|
+
return type.name === markRange.mark.type.name;
|
|
2306
|
+
})
|
|
2307
|
+
.filter(markRange => objectIncludes(markRange.mark.attrs, attributes, { strict: false }))
|
|
2308
|
+
.reduce((sum, markRange) => sum + markRange.to - markRange.from, 0);
|
|
2309
|
+
// calculate range of marks that excludes the searched mark
|
|
2310
|
+
// for example `code` doesn’t allow any other marks
|
|
2311
|
+
const excludedRange = markRanges
|
|
2312
|
+
.filter(markRange => {
|
|
2313
|
+
if (!type) {
|
|
2314
|
+
return true;
|
|
2315
|
+
}
|
|
2316
|
+
return markRange.mark.type !== type
|
|
2317
|
+
&& markRange.mark.type.excludes(type);
|
|
2318
|
+
})
|
|
2319
|
+
.reduce((sum, markRange) => sum + markRange.to - markRange.from, 0);
|
|
2320
|
+
// we only include the result of `excludedRange`
|
|
2321
|
+
// if there is a match at all
|
|
2322
|
+
const range = matchedRange > 0
|
|
2323
|
+
? matchedRange + excludedRange
|
|
2324
|
+
: matchedRange;
|
|
2325
|
+
return range >= selectionRange;
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
function isActive(state, name, attributes = {}) {
|
|
2329
|
+
if (!name) {
|
|
2330
|
+
return isNodeActive(state, null, attributes) || isMarkActive(state, null, attributes);
|
|
2331
|
+
}
|
|
2332
|
+
const schemaType = getSchemaTypeNameByName(name, state.schema);
|
|
2333
|
+
if (schemaType === 'node') {
|
|
2334
|
+
return isNodeActive(state, name, attributes);
|
|
2335
|
+
}
|
|
2336
|
+
if (schemaType === 'mark') {
|
|
2337
|
+
return isMarkActive(state, name, attributes);
|
|
2338
|
+
}
|
|
2339
|
+
return false;
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
function isList(name, extensions) {
|
|
2343
|
+
const { nodeExtensions } = splitExtensions(extensions);
|
|
2344
|
+
const extension = nodeExtensions.find(item => item.name === name);
|
|
2345
|
+
if (!extension) {
|
|
2346
|
+
return false;
|
|
2347
|
+
}
|
|
2348
|
+
const context = {
|
|
2349
|
+
name: extension.name,
|
|
2350
|
+
options: extension.options,
|
|
2351
|
+
storage: extension.storage,
|
|
2352
|
+
};
|
|
2353
|
+
const group = callOrReturn(getExtensionField(extension, 'group', context));
|
|
2354
|
+
if (typeof group !== 'string') {
|
|
2355
|
+
return false;
|
|
2356
|
+
}
|
|
2357
|
+
return group.split(' ').includes('list');
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
function isNodeEmpty(node) {
|
|
2361
|
+
var _a;
|
|
2362
|
+
const defaultContent = (_a = node.type.createAndFill()) === null || _a === void 0 ? void 0 : _a.toJSON();
|
|
2363
|
+
const content = node.toJSON();
|
|
2364
|
+
return JSON.stringify(defaultContent) === JSON.stringify(content);
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
function isNodeSelection(value) {
|
|
2368
|
+
return value instanceof prosemirrorState.NodeSelection;
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
function posToDOMRect(view, from, to) {
|
|
2372
|
+
const minPos = 0;
|
|
2373
|
+
const maxPos = view.state.doc.content.size;
|
|
2374
|
+
const resolvedFrom = minMax(from, minPos, maxPos);
|
|
2375
|
+
const resolvedEnd = minMax(to, minPos, maxPos);
|
|
2376
|
+
const start = view.coordsAtPos(resolvedFrom);
|
|
2377
|
+
const end = view.coordsAtPos(resolvedEnd, -1);
|
|
2378
|
+
const top = Math.min(start.top, end.top);
|
|
2379
|
+
const bottom = Math.max(start.bottom, end.bottom);
|
|
2380
|
+
const left = Math.min(start.left, end.left);
|
|
2381
|
+
const right = Math.max(start.right, end.right);
|
|
2382
|
+
const width = right - left;
|
|
2383
|
+
const height = bottom - top;
|
|
2384
|
+
const x = left;
|
|
2385
|
+
const y = top;
|
|
2386
|
+
const data = {
|
|
2387
|
+
top,
|
|
2388
|
+
bottom,
|
|
2389
|
+
left,
|
|
2390
|
+
right,
|
|
2391
|
+
width,
|
|
2392
|
+
height,
|
|
2393
|
+
x,
|
|
2394
|
+
y,
|
|
2395
|
+
};
|
|
2396
|
+
return {
|
|
2397
|
+
...data,
|
|
2398
|
+
toJSON: () => data,
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
function canSetMark(state, tr, newMarkType) {
|
|
2403
|
+
var _a;
|
|
2404
|
+
const { selection } = tr;
|
|
2405
|
+
let cursor = null;
|
|
2406
|
+
if (isTextSelection(selection)) {
|
|
2407
|
+
cursor = selection.$cursor;
|
|
2408
|
+
}
|
|
2409
|
+
if (cursor) {
|
|
2410
|
+
const currentMarks = (_a = state.storedMarks) !== null && _a !== void 0 ? _a : cursor.marks();
|
|
2411
|
+
// There can be no current marks that exclude the new mark
|
|
2412
|
+
return !!newMarkType.isInSet(currentMarks) || !currentMarks.some(mark => mark.type.excludes(newMarkType));
|
|
2413
|
+
}
|
|
2414
|
+
const { ranges } = selection;
|
|
2415
|
+
return ranges.some(({ $from, $to }) => {
|
|
2416
|
+
let someNodeSupportsMark = $from.depth === 0 ? state.doc.inlineContent && state.doc.type.allowsMarkType(newMarkType) : false;
|
|
2417
|
+
state.doc.nodesBetween($from.pos, $to.pos, (node, _pos, parent) => {
|
|
2418
|
+
// If we already found a mark that we can enable, return false to bypass the remaining search
|
|
2419
|
+
if (someNodeSupportsMark) {
|
|
2420
|
+
return false;
|
|
2421
|
+
}
|
|
2422
|
+
if (node.isInline) {
|
|
2423
|
+
const parentAllowsMarkType = !parent || parent.type.allowsMarkType(newMarkType);
|
|
2424
|
+
const currentMarksAllowMarkType = !!newMarkType.isInSet(node.marks) || !node.marks.some(otherMark => otherMark.type.excludes(newMarkType));
|
|
2425
|
+
someNodeSupportsMark = parentAllowsMarkType && currentMarksAllowMarkType;
|
|
2426
|
+
}
|
|
2427
|
+
return !someNodeSupportsMark;
|
|
2428
|
+
});
|
|
2429
|
+
return someNodeSupportsMark;
|
|
2430
|
+
});
|
|
2431
|
+
}
|
|
2432
|
+
const setMark = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
|
|
2433
|
+
const { selection } = tr;
|
|
2434
|
+
const { empty, ranges } = selection;
|
|
2435
|
+
const type = getMarkType(typeOrName, state.schema);
|
|
2436
|
+
if (dispatch) {
|
|
2437
|
+
if (empty) {
|
|
2438
|
+
const oldAttributes = getMarkAttributes(state, type);
|
|
2439
|
+
tr.addStoredMark(type.create({
|
|
2440
|
+
...oldAttributes,
|
|
2441
|
+
...attributes,
|
|
2442
|
+
}));
|
|
2443
|
+
}
|
|
2444
|
+
else {
|
|
2445
|
+
ranges.forEach(range => {
|
|
2446
|
+
const from = range.$from.pos;
|
|
2447
|
+
const to = range.$to.pos;
|
|
2448
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
2449
|
+
const trimmedFrom = Math.max(pos, from);
|
|
2450
|
+
const trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
2451
|
+
const someHasMark = node.marks.find(mark => mark.type === type);
|
|
2452
|
+
// if there is already a mark of this type
|
|
2453
|
+
// we know that we have to merge its attributes
|
|
2454
|
+
// otherwise we add a fresh new mark
|
|
2455
|
+
if (someHasMark) {
|
|
2456
|
+
node.marks.forEach(mark => {
|
|
2457
|
+
if (type === mark.type) {
|
|
2458
|
+
tr.addMark(trimmedFrom, trimmedTo, type.create({
|
|
2459
|
+
...mark.attrs,
|
|
2460
|
+
...attributes,
|
|
2461
|
+
}));
|
|
2462
|
+
}
|
|
2463
|
+
});
|
|
2464
|
+
}
|
|
2465
|
+
else {
|
|
2466
|
+
tr.addMark(trimmedFrom, trimmedTo, type.create(attributes));
|
|
2467
|
+
}
|
|
2468
|
+
});
|
|
2469
|
+
});
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
return canSetMark(state, tr, type);
|
|
2473
|
+
};
|
|
2474
|
+
|
|
2475
|
+
const setMeta = (key, value) => ({ tr }) => {
|
|
2476
|
+
tr.setMeta(key, value);
|
|
2477
|
+
return true;
|
|
2478
|
+
};
|
|
2479
|
+
|
|
2480
|
+
const setNode = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) => {
|
|
2481
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2482
|
+
// TODO: use a fallback like insertContent?
|
|
2483
|
+
if (!type.isTextblock) {
|
|
2484
|
+
console.warn('[tiptap warn]: Currently "setNode()" only supports text block nodes.');
|
|
2485
|
+
return false;
|
|
2486
|
+
}
|
|
2487
|
+
return chain()
|
|
2488
|
+
// try to convert node to default node if needed
|
|
2489
|
+
.command(({ commands }) => {
|
|
2490
|
+
const canSetBlock = prosemirrorCommands.setBlockType(type, attributes)(state);
|
|
2491
|
+
if (canSetBlock) {
|
|
2492
|
+
return true;
|
|
2493
|
+
}
|
|
2494
|
+
return commands.clearNodes();
|
|
2495
|
+
})
|
|
2496
|
+
.command(({ state: updatedState }) => {
|
|
2497
|
+
return prosemirrorCommands.setBlockType(type, attributes)(updatedState, dispatch);
|
|
2498
|
+
})
|
|
2499
|
+
.run();
|
|
2500
|
+
};
|
|
2501
|
+
|
|
2502
|
+
const setNodeSelection = position => ({ tr, dispatch }) => {
|
|
2503
|
+
if (dispatch) {
|
|
2504
|
+
const { doc } = tr;
|
|
2505
|
+
const from = minMax(position, 0, doc.content.size);
|
|
2506
|
+
const selection = prosemirrorState.NodeSelection.create(doc, from);
|
|
2507
|
+
tr.setSelection(selection);
|
|
2508
|
+
}
|
|
2509
|
+
return true;
|
|
2510
|
+
};
|
|
2511
|
+
|
|
2512
|
+
const setTextSelection = position => ({ tr, dispatch }) => {
|
|
2513
|
+
if (dispatch) {
|
|
2514
|
+
const { doc } = tr;
|
|
2515
|
+
const { from, to } = typeof position === 'number'
|
|
2516
|
+
? { from: position, to: position }
|
|
2517
|
+
: position;
|
|
2518
|
+
const minPos = prosemirrorState.TextSelection.atStart(doc).from;
|
|
2519
|
+
const maxPos = prosemirrorState.TextSelection.atEnd(doc).to;
|
|
2520
|
+
const resolvedFrom = minMax(from, minPos, maxPos);
|
|
2521
|
+
const resolvedEnd = minMax(to, minPos, maxPos);
|
|
2522
|
+
const selection = prosemirrorState.TextSelection.create(doc, resolvedFrom, resolvedEnd);
|
|
2523
|
+
tr.setSelection(selection);
|
|
2524
|
+
}
|
|
2525
|
+
return true;
|
|
2526
|
+
};
|
|
2527
|
+
|
|
2528
|
+
const sinkListItem = typeOrName => ({ state, dispatch }) => {
|
|
2529
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2530
|
+
return prosemirrorSchemaList.sinkListItem(type)(state, dispatch);
|
|
2531
|
+
};
|
|
2532
|
+
|
|
2533
|
+
function getSplittedAttributes(extensionAttributes, typeName, attributes) {
|
|
2067
2534
|
return Object.fromEntries(Object
|
|
2068
2535
|
.entries(attributes)
|
|
2069
2536
|
.filter(([name]) => {
|
|
@@ -2235,42 +2702,6 @@
|
|
|
2235
2702
|
return true;
|
|
2236
2703
|
};
|
|
2237
2704
|
|
|
2238
|
-
function findParentNodeClosestToPos($pos, predicate) {
|
|
2239
|
-
for (let i = $pos.depth; i > 0; i -= 1) {
|
|
2240
|
-
const node = $pos.node(i);
|
|
2241
|
-
if (predicate(node)) {
|
|
2242
|
-
return {
|
|
2243
|
-
pos: i > 0 ? $pos.before(i) : 0,
|
|
2244
|
-
start: $pos.start(i),
|
|
2245
|
-
depth: i,
|
|
2246
|
-
node,
|
|
2247
|
-
};
|
|
2248
|
-
}
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
|
|
2252
|
-
function findParentNode(predicate) {
|
|
2253
|
-
return (selection) => findParentNodeClosestToPos(selection.$from, predicate);
|
|
2254
|
-
}
|
|
2255
|
-
|
|
2256
|
-
function isList(name, extensions) {
|
|
2257
|
-
const { nodeExtensions } = splitExtensions(extensions);
|
|
2258
|
-
const extension = nodeExtensions.find(item => item.name === name);
|
|
2259
|
-
if (!extension) {
|
|
2260
|
-
return false;
|
|
2261
|
-
}
|
|
2262
|
-
const context = {
|
|
2263
|
-
name: extension.name,
|
|
2264
|
-
options: extension.options,
|
|
2265
|
-
storage: extension.storage,
|
|
2266
|
-
};
|
|
2267
|
-
const group = callOrReturn(getExtensionField(extension, 'group', context));
|
|
2268
|
-
if (typeof group !== 'string') {
|
|
2269
|
-
return false;
|
|
2270
|
-
}
|
|
2271
|
-
return group.split(' ').includes('list');
|
|
2272
|
-
}
|
|
2273
|
-
|
|
2274
2705
|
const joinListBackwards = (tr, listType) => {
|
|
2275
2706
|
const list = findParentNode(node => node.type === listType)(tr.selection);
|
|
2276
2707
|
if (!list) {
|
|
@@ -2352,73 +2783,6 @@
|
|
|
2352
2783
|
.run();
|
|
2353
2784
|
};
|
|
2354
2785
|
|
|
2355
|
-
function isMarkActive(state, typeOrName, attributes = {}) {
|
|
2356
|
-
const { empty, ranges } = state.selection;
|
|
2357
|
-
const type = typeOrName
|
|
2358
|
-
? getMarkType(typeOrName, state.schema)
|
|
2359
|
-
: null;
|
|
2360
|
-
if (empty) {
|
|
2361
|
-
return !!(state.storedMarks || state.selection.$from.marks())
|
|
2362
|
-
.filter(mark => {
|
|
2363
|
-
if (!type) {
|
|
2364
|
-
return true;
|
|
2365
|
-
}
|
|
2366
|
-
return type.name === mark.type.name;
|
|
2367
|
-
})
|
|
2368
|
-
.find(mark => objectIncludes(mark.attrs, attributes, { strict: false }));
|
|
2369
|
-
}
|
|
2370
|
-
let selectionRange = 0;
|
|
2371
|
-
const markRanges = [];
|
|
2372
|
-
ranges.forEach(({ $from, $to }) => {
|
|
2373
|
-
const from = $from.pos;
|
|
2374
|
-
const to = $to.pos;
|
|
2375
|
-
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
2376
|
-
if (!node.isText && !node.marks.length) {
|
|
2377
|
-
return;
|
|
2378
|
-
}
|
|
2379
|
-
const relativeFrom = Math.max(from, pos);
|
|
2380
|
-
const relativeTo = Math.min(to, pos + node.nodeSize);
|
|
2381
|
-
const range = relativeTo - relativeFrom;
|
|
2382
|
-
selectionRange += range;
|
|
2383
|
-
markRanges.push(...node.marks.map(mark => ({
|
|
2384
|
-
mark,
|
|
2385
|
-
from: relativeFrom,
|
|
2386
|
-
to: relativeTo,
|
|
2387
|
-
})));
|
|
2388
|
-
});
|
|
2389
|
-
});
|
|
2390
|
-
if (selectionRange === 0) {
|
|
2391
|
-
return false;
|
|
2392
|
-
}
|
|
2393
|
-
// calculate range of matched mark
|
|
2394
|
-
const matchedRange = markRanges
|
|
2395
|
-
.filter(markRange => {
|
|
2396
|
-
if (!type) {
|
|
2397
|
-
return true;
|
|
2398
|
-
}
|
|
2399
|
-
return type.name === markRange.mark.type.name;
|
|
2400
|
-
})
|
|
2401
|
-
.filter(markRange => objectIncludes(markRange.mark.attrs, attributes, { strict: false }))
|
|
2402
|
-
.reduce((sum, markRange) => sum + markRange.to - markRange.from, 0);
|
|
2403
|
-
// calculate range of marks that excludes the searched mark
|
|
2404
|
-
// for example `code` doesn’t allow any other marks
|
|
2405
|
-
const excludedRange = markRanges
|
|
2406
|
-
.filter(markRange => {
|
|
2407
|
-
if (!type) {
|
|
2408
|
-
return true;
|
|
2409
|
-
}
|
|
2410
|
-
return markRange.mark.type !== type
|
|
2411
|
-
&& markRange.mark.type.excludes(type);
|
|
2412
|
-
})
|
|
2413
|
-
.reduce((sum, markRange) => sum + markRange.to - markRange.from, 0);
|
|
2414
|
-
// we only include the result of `excludedRange`
|
|
2415
|
-
// if there is a match at all
|
|
2416
|
-
const range = matchedRange > 0
|
|
2417
|
-
? matchedRange + excludedRange
|
|
2418
|
-
: matchedRange;
|
|
2419
|
-
return range >= selectionRange;
|
|
2420
|
-
}
|
|
2421
|
-
|
|
2422
2786
|
const toggleMark = (typeOrName, attributes = {}, options = {}) => ({ state, commands }) => {
|
|
2423
2787
|
const { extendEmptyMarkRange = false } = options;
|
|
2424
2788
|
const type = getMarkType(typeOrName, state.schema);
|
|
@@ -2806,78 +3170,10 @@
|
|
|
2806
3170
|
ClipboardTextSerializer: ClipboardTextSerializer,
|
|
2807
3171
|
Commands: Commands,
|
|
2808
3172
|
Editable: Editable,
|
|
2809
|
-
FocusEvents: FocusEvents,
|
|
2810
|
-
Keymap: Keymap,
|
|
2811
|
-
Tabindex: Tabindex
|
|
2812
|
-
});
|
|
2813
|
-
|
|
2814
|
-
function getNodeAttributes(state, typeOrName) {
|
|
2815
|
-
const type = getNodeType(typeOrName, state.schema);
|
|
2816
|
-
const { from, to } = state.selection;
|
|
2817
|
-
const nodes = [];
|
|
2818
|
-
state.doc.nodesBetween(from, to, node => {
|
|
2819
|
-
nodes.push(node);
|
|
2820
|
-
});
|
|
2821
|
-
const node = nodes
|
|
2822
|
-
.reverse()
|
|
2823
|
-
.find(nodeItem => nodeItem.type.name === type.name);
|
|
2824
|
-
if (!node) {
|
|
2825
|
-
return {};
|
|
2826
|
-
}
|
|
2827
|
-
return { ...node.attrs };
|
|
2828
|
-
}
|
|
2829
|
-
|
|
2830
|
-
function getAttributes(state, typeOrName) {
|
|
2831
|
-
const schemaType = getSchemaTypeNameByName(typeof typeOrName === 'string'
|
|
2832
|
-
? typeOrName
|
|
2833
|
-
: typeOrName.name, state.schema);
|
|
2834
|
-
if (schemaType === 'node') {
|
|
2835
|
-
return getNodeAttributes(state, typeOrName);
|
|
2836
|
-
}
|
|
2837
|
-
if (schemaType === 'mark') {
|
|
2838
|
-
return getMarkAttributes(state, typeOrName);
|
|
2839
|
-
}
|
|
2840
|
-
return {};
|
|
2841
|
-
}
|
|
2842
|
-
|
|
2843
|
-
function getHTMLFromFragment(fragment, schema) {
|
|
2844
|
-
const documentFragment = prosemirrorModel.DOMSerializer
|
|
2845
|
-
.fromSchema(schema)
|
|
2846
|
-
.serializeFragment(fragment);
|
|
2847
|
-
const temporaryDocument = document.implementation.createHTMLDocument();
|
|
2848
|
-
const container = temporaryDocument.createElement('div');
|
|
2849
|
-
container.appendChild(documentFragment);
|
|
2850
|
-
return container.innerHTML;
|
|
2851
|
-
}
|
|
2852
|
-
|
|
2853
|
-
function getText(node, options) {
|
|
2854
|
-
const range = {
|
|
2855
|
-
from: 0,
|
|
2856
|
-
to: node.content.size,
|
|
2857
|
-
};
|
|
2858
|
-
return getTextBetween(node, range, options);
|
|
2859
|
-
}
|
|
2860
|
-
|
|
2861
|
-
function isActive(state, name, attributes = {}) {
|
|
2862
|
-
if (!name) {
|
|
2863
|
-
return isNodeActive(state, null, attributes) || isMarkActive(state, null, attributes);
|
|
2864
|
-
}
|
|
2865
|
-
const schemaType = getSchemaTypeNameByName(name, state.schema);
|
|
2866
|
-
if (schemaType === 'node') {
|
|
2867
|
-
return isNodeActive(state, name, attributes);
|
|
2868
|
-
}
|
|
2869
|
-
if (schemaType === 'mark') {
|
|
2870
|
-
return isMarkActive(state, name, attributes);
|
|
2871
|
-
}
|
|
2872
|
-
return false;
|
|
2873
|
-
}
|
|
2874
|
-
|
|
2875
|
-
function isNodeEmpty(node) {
|
|
2876
|
-
var _a;
|
|
2877
|
-
const defaultContent = (_a = node.type.createAndFill()) === null || _a === void 0 ? void 0 : _a.toJSON();
|
|
2878
|
-
const content = node.toJSON();
|
|
2879
|
-
return JSON.stringify(defaultContent) === JSON.stringify(content);
|
|
2880
|
-
}
|
|
3173
|
+
FocusEvents: FocusEvents,
|
|
3174
|
+
Keymap: Keymap,
|
|
3175
|
+
Tabindex: Tabindex
|
|
3176
|
+
});
|
|
2881
3177
|
|
|
2882
3178
|
const style = `.ProseMirror {
|
|
2883
3179
|
position: relative;
|
|
@@ -3183,407 +3479,143 @@ img.ProseMirror-separator {
|
|
|
3183
3479
|
/**
|
|
3184
3480
|
* Creates all node views.
|
|
3185
3481
|
*/
|
|
3186
|
-
createNodeViews() {
|
|
3187
|
-
this.view.setProps({
|
|
3188
|
-
nodeViews: this.extensionManager.nodeViews,
|
|
3189
|
-
});
|
|
3190
|
-
}
|
|
3191
|
-
captureTransaction(fn) {
|
|
3192
|
-
this.isCapturingTransaction = true;
|
|
3193
|
-
fn();
|
|
3194
|
-
this.isCapturingTransaction = false;
|
|
3195
|
-
const tr = this.capturedTransaction;
|
|
3196
|
-
this.capturedTransaction = null;
|
|
3197
|
-
return tr;
|
|
3198
|
-
}
|
|
3199
|
-
/**
|
|
3200
|
-
* The callback over which to send transactions (state updates) produced by the view.
|
|
3201
|
-
*
|
|
3202
|
-
* @param transaction An editor state transaction
|
|
3203
|
-
*/
|
|
3204
|
-
dispatchTransaction(transaction) {
|
|
3205
|
-
if (this.isCapturingTransaction) {
|
|
3206
|
-
if (!this.capturedTransaction) {
|
|
3207
|
-
this.capturedTransaction = transaction;
|
|
3208
|
-
return;
|
|
3209
|
-
}
|
|
3210
|
-
transaction.steps.forEach(step => { var _a; return (_a = this.capturedTransaction) === null || _a === void 0 ? void 0 : _a.step(step); });
|
|
3211
|
-
return;
|
|
3212
|
-
}
|
|
3213
|
-
const state = this.state.apply(transaction);
|
|
3214
|
-
const selectionHasChanged = !this.state.selection.eq(state.selection);
|
|
3215
|
-
this.view.updateState(state);
|
|
3216
|
-
this.emit('transaction', {
|
|
3217
|
-
editor: this,
|
|
3218
|
-
transaction,
|
|
3219
|
-
});
|
|
3220
|
-
if (selectionHasChanged) {
|
|
3221
|
-
this.emit('selectionUpdate', {
|
|
3222
|
-
editor: this,
|
|
3223
|
-
transaction,
|
|
3224
|
-
});
|
|
3225
|
-
}
|
|
3226
|
-
const focus = transaction.getMeta('focus');
|
|
3227
|
-
const blur = transaction.getMeta('blur');
|
|
3228
|
-
if (focus) {
|
|
3229
|
-
this.emit('focus', {
|
|
3230
|
-
editor: this,
|
|
3231
|
-
event: focus.event,
|
|
3232
|
-
transaction,
|
|
3233
|
-
});
|
|
3234
|
-
}
|
|
3235
|
-
if (blur) {
|
|
3236
|
-
this.emit('blur', {
|
|
3237
|
-
editor: this,
|
|
3238
|
-
event: blur.event,
|
|
3239
|
-
transaction,
|
|
3240
|
-
});
|
|
3241
|
-
}
|
|
3242
|
-
if (!transaction.docChanged || transaction.getMeta('preventUpdate')) {
|
|
3243
|
-
return;
|
|
3244
|
-
}
|
|
3245
|
-
this.emit('update', {
|
|
3246
|
-
editor: this,
|
|
3247
|
-
transaction,
|
|
3248
|
-
});
|
|
3249
|
-
}
|
|
3250
|
-
/**
|
|
3251
|
-
* Get attributes of the currently selected node or mark.
|
|
3252
|
-
*/
|
|
3253
|
-
getAttributes(nameOrType) {
|
|
3254
|
-
return getAttributes(this.state, nameOrType);
|
|
3255
|
-
}
|
|
3256
|
-
isActive(nameOrAttributes, attributesOrUndefined) {
|
|
3257
|
-
const name = typeof nameOrAttributes === 'string'
|
|
3258
|
-
? nameOrAttributes
|
|
3259
|
-
: null;
|
|
3260
|
-
const attributes = typeof nameOrAttributes === 'string'
|
|
3261
|
-
? attributesOrUndefined
|
|
3262
|
-
: nameOrAttributes;
|
|
3263
|
-
return isActive(this.state, name, attributes);
|
|
3264
|
-
}
|
|
3265
|
-
/**
|
|
3266
|
-
* Get the document as JSON.
|
|
3267
|
-
*/
|
|
3268
|
-
getJSON() {
|
|
3269
|
-
return this.state.doc.toJSON();
|
|
3270
|
-
}
|
|
3271
|
-
/**
|
|
3272
|
-
* Get the document as HTML.
|
|
3273
|
-
*/
|
|
3274
|
-
getHTML() {
|
|
3275
|
-
return getHTMLFromFragment(this.state.doc.content, this.schema);
|
|
3276
|
-
}
|
|
3277
|
-
/**
|
|
3278
|
-
* Get the document as text.
|
|
3279
|
-
*/
|
|
3280
|
-
getText(options) {
|
|
3281
|
-
const { blockSeparator = '\n\n', textSerializers = {}, } = options || {};
|
|
3282
|
-
return getText(this.state.doc, {
|
|
3283
|
-
blockSeparator,
|
|
3284
|
-
textSerializers: {
|
|
3285
|
-
...textSerializers,
|
|
3286
|
-
...getTextSerializersFromSchema(this.schema),
|
|
3287
|
-
},
|
|
3288
|
-
});
|
|
3289
|
-
}
|
|
3290
|
-
/**
|
|
3291
|
-
* Check if there is no content.
|
|
3292
|
-
*/
|
|
3293
|
-
get isEmpty() {
|
|
3294
|
-
return isNodeEmpty(this.state.doc);
|
|
3295
|
-
}
|
|
3296
|
-
/**
|
|
3297
|
-
* Get the number of characters for the current document.
|
|
3298
|
-
*
|
|
3299
|
-
* @deprecated
|
|
3300
|
-
*/
|
|
3301
|
-
getCharacterCount() {
|
|
3302
|
-
console.warn('[tiptap warn]: "editor.getCharacterCount()" is deprecated. Please use "editor.storage.characterCount.characters()" instead.');
|
|
3303
|
-
return this.state.doc.content.size - 2;
|
|
3304
|
-
}
|
|
3305
|
-
/**
|
|
3306
|
-
* Destroy the editor.
|
|
3307
|
-
*/
|
|
3308
|
-
destroy() {
|
|
3309
|
-
this.emit('destroy');
|
|
3310
|
-
if (this.view) {
|
|
3311
|
-
this.view.destroy();
|
|
3312
|
-
}
|
|
3313
|
-
this.removeAllListeners();
|
|
3314
|
-
}
|
|
3315
|
-
/**
|
|
3316
|
-
* Check if the editor is already destroyed.
|
|
3317
|
-
*/
|
|
3318
|
-
get isDestroyed() {
|
|
3319
|
-
var _a;
|
|
3320
|
-
// @ts-ignore
|
|
3321
|
-
return !((_a = this.view) === null || _a === void 0 ? void 0 : _a.docView);
|
|
3322
|
-
}
|
|
3323
|
-
}
|
|
3324
|
-
|
|
3325
|
-
/**
|
|
3326
|
-
* Returns a new `Transform` based on all steps of the passed transactions.
|
|
3327
|
-
*/
|
|
3328
|
-
function combineTransactionSteps(oldDoc, transactions) {
|
|
3329
|
-
const transform = new prosemirrorTransform.Transform(oldDoc);
|
|
3330
|
-
transactions.forEach(transaction => {
|
|
3331
|
-
transaction.steps.forEach(step => {
|
|
3332
|
-
transform.step(step);
|
|
3333
|
-
});
|
|
3334
|
-
});
|
|
3335
|
-
return transform;
|
|
3336
|
-
}
|
|
3337
|
-
|
|
3338
|
-
function findChildren(node, predicate) {
|
|
3339
|
-
const nodesWithPos = [];
|
|
3340
|
-
node.descendants((child, pos) => {
|
|
3341
|
-
if (predicate(child)) {
|
|
3342
|
-
nodesWithPos.push({
|
|
3343
|
-
node: child,
|
|
3344
|
-
pos,
|
|
3345
|
-
});
|
|
3346
|
-
}
|
|
3347
|
-
});
|
|
3348
|
-
return nodesWithPos;
|
|
3349
|
-
}
|
|
3350
|
-
|
|
3351
|
-
/**
|
|
3352
|
-
* Same as `findChildren` but searches only within a `range`.
|
|
3353
|
-
*/
|
|
3354
|
-
function findChildrenInRange(node, range, predicate) {
|
|
3355
|
-
const nodesWithPos = [];
|
|
3356
|
-
// if (range.from === range.to) {
|
|
3357
|
-
// const nodeAt = node.nodeAt(range.from)
|
|
3358
|
-
// if (nodeAt) {
|
|
3359
|
-
// nodesWithPos.push({
|
|
3360
|
-
// node: nodeAt,
|
|
3361
|
-
// pos: range.from,
|
|
3362
|
-
// })
|
|
3363
|
-
// }
|
|
3364
|
-
// }
|
|
3365
|
-
node.nodesBetween(range.from, range.to, (child, pos) => {
|
|
3366
|
-
if (predicate(child)) {
|
|
3367
|
-
nodesWithPos.push({
|
|
3368
|
-
node: child,
|
|
3369
|
-
pos,
|
|
3370
|
-
});
|
|
3371
|
-
}
|
|
3372
|
-
});
|
|
3373
|
-
return nodesWithPos;
|
|
3374
|
-
}
|
|
3375
|
-
|
|
3376
|
-
function getSchema(extensions) {
|
|
3377
|
-
const resolvedExtensions = ExtensionManager.resolve(extensions);
|
|
3378
|
-
return getSchemaByResolvedExtensions(resolvedExtensions);
|
|
3379
|
-
}
|
|
3380
|
-
|
|
3381
|
-
function generateHTML(doc, extensions) {
|
|
3382
|
-
const schema = getSchema(extensions);
|
|
3383
|
-
const contentNode = prosemirrorModel.Node.fromJSON(schema, doc);
|
|
3384
|
-
return getHTMLFromFragment(contentNode.content, schema);
|
|
3385
|
-
}
|
|
3386
|
-
|
|
3387
|
-
function generateJSON(html, extensions) {
|
|
3388
|
-
const schema = getSchema(extensions);
|
|
3389
|
-
const dom = elementFromString(html);
|
|
3390
|
-
return prosemirrorModel.DOMParser.fromSchema(schema)
|
|
3391
|
-
.parse(dom)
|
|
3392
|
-
.toJSON();
|
|
3393
|
-
}
|
|
3394
|
-
|
|
3395
|
-
function generateText(doc, extensions, options) {
|
|
3396
|
-
const { blockSeparator = '\n\n', textSerializers = {}, } = options || {};
|
|
3397
|
-
const schema = getSchema(extensions);
|
|
3398
|
-
const contentNode = prosemirrorModel.Node.fromJSON(schema, doc);
|
|
3399
|
-
return getText(contentNode, {
|
|
3400
|
-
blockSeparator,
|
|
3401
|
-
textSerializers: {
|
|
3402
|
-
...textSerializers,
|
|
3403
|
-
...getTextSerializersFromSchema(schema),
|
|
3404
|
-
},
|
|
3405
|
-
});
|
|
3406
|
-
}
|
|
3407
|
-
|
|
3408
|
-
/**
|
|
3409
|
-
* Removes duplicated values within an array.
|
|
3410
|
-
* Supports numbers, strings and objects.
|
|
3411
|
-
*/
|
|
3412
|
-
function removeDuplicates(array, by = JSON.stringify) {
|
|
3413
|
-
const seen = {};
|
|
3414
|
-
return array.filter(item => {
|
|
3415
|
-
const key = by(item);
|
|
3416
|
-
return Object.prototype.hasOwnProperty.call(seen, key)
|
|
3417
|
-
? false
|
|
3418
|
-
: (seen[key] = true);
|
|
3419
|
-
});
|
|
3420
|
-
}
|
|
3421
|
-
|
|
3422
|
-
/**
|
|
3423
|
-
* Removes duplicated ranges and ranges that are
|
|
3424
|
-
* fully captured by other ranges.
|
|
3425
|
-
*/
|
|
3426
|
-
function simplifyChangedRanges(changes) {
|
|
3427
|
-
const uniqueChanges = removeDuplicates(changes);
|
|
3428
|
-
return uniqueChanges.length === 1
|
|
3429
|
-
? uniqueChanges
|
|
3430
|
-
: uniqueChanges.filter((change, index) => {
|
|
3431
|
-
const rest = uniqueChanges.filter((_, i) => i !== index);
|
|
3432
|
-
return !rest.some(otherChange => {
|
|
3433
|
-
return change.oldRange.from >= otherChange.oldRange.from
|
|
3434
|
-
&& change.oldRange.to <= otherChange.oldRange.to
|
|
3435
|
-
&& change.newRange.from >= otherChange.newRange.from
|
|
3436
|
-
&& change.newRange.to <= otherChange.newRange.to;
|
|
3437
|
-
});
|
|
3482
|
+
createNodeViews() {
|
|
3483
|
+
this.view.setProps({
|
|
3484
|
+
nodeViews: this.extensionManager.nodeViews,
|
|
3438
3485
|
});
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3486
|
+
}
|
|
3487
|
+
captureTransaction(fn) {
|
|
3488
|
+
this.isCapturingTransaction = true;
|
|
3489
|
+
fn();
|
|
3490
|
+
this.isCapturingTransaction = false;
|
|
3491
|
+
const tr = this.capturedTransaction;
|
|
3492
|
+
this.capturedTransaction = null;
|
|
3493
|
+
return tr;
|
|
3494
|
+
}
|
|
3495
|
+
/**
|
|
3496
|
+
* The callback over which to send transactions (state updates) produced by the view.
|
|
3497
|
+
*
|
|
3498
|
+
* @param transaction An editor state transaction
|
|
3499
|
+
*/
|
|
3500
|
+
dispatchTransaction(transaction) {
|
|
3501
|
+
if (this.isCapturingTransaction) {
|
|
3502
|
+
if (!this.capturedTransaction) {
|
|
3503
|
+
this.capturedTransaction = transaction;
|
|
3455
3504
|
return;
|
|
3456
3505
|
}
|
|
3457
|
-
|
|
3506
|
+
transaction.steps.forEach(step => { var _a; return (_a = this.capturedTransaction) === null || _a === void 0 ? void 0 : _a.step(step); });
|
|
3507
|
+
return;
|
|
3458
3508
|
}
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3509
|
+
const state = this.state.apply(transaction);
|
|
3510
|
+
const selectionHasChanged = !this.state.selection.eq(state.selection);
|
|
3511
|
+
this.view.updateState(state);
|
|
3512
|
+
this.emit('transaction', {
|
|
3513
|
+
editor: this,
|
|
3514
|
+
transaction,
|
|
3515
|
+
});
|
|
3516
|
+
if (selectionHasChanged) {
|
|
3517
|
+
this.emit('selectionUpdate', {
|
|
3518
|
+
editor: this,
|
|
3519
|
+
transaction,
|
|
3462
3520
|
});
|
|
3463
3521
|
}
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
from: oldStart,
|
|
3472
|
-
to: oldEnd,
|
|
3473
|
-
},
|
|
3474
|
-
newRange: {
|
|
3475
|
-
from: newStart,
|
|
3476
|
-
to: newEnd,
|
|
3477
|
-
},
|
|
3522
|
+
const focus = transaction.getMeta('focus');
|
|
3523
|
+
const blur = transaction.getMeta('blur');
|
|
3524
|
+
if (focus) {
|
|
3525
|
+
this.emit('focus', {
|
|
3526
|
+
editor: this,
|
|
3527
|
+
event: focus.event,
|
|
3528
|
+
transaction,
|
|
3478
3529
|
});
|
|
3479
|
-
});
|
|
3480
|
-
});
|
|
3481
|
-
return simplifyChangedRanges(changes);
|
|
3482
|
-
}
|
|
3483
|
-
|
|
3484
|
-
function getDebugJSON(node, startOffset = 0) {
|
|
3485
|
-
const isTopNode = node.type === node.type.schema.topNodeType;
|
|
3486
|
-
const increment = isTopNode ? 0 : 1;
|
|
3487
|
-
const from = startOffset;
|
|
3488
|
-
const to = from + node.nodeSize;
|
|
3489
|
-
const marks = node.marks.map(mark => {
|
|
3490
|
-
const output = {
|
|
3491
|
-
type: mark.type.name,
|
|
3492
|
-
};
|
|
3493
|
-
if (Object.keys(mark.attrs).length) {
|
|
3494
|
-
output.attrs = { ...mark.attrs };
|
|
3495
3530
|
}
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3531
|
+
if (blur) {
|
|
3532
|
+
this.emit('blur', {
|
|
3533
|
+
editor: this,
|
|
3534
|
+
event: blur.event,
|
|
3535
|
+
transaction,
|
|
3536
|
+
});
|
|
3537
|
+
}
|
|
3538
|
+
if (!transaction.docChanged || transaction.getMeta('preventUpdate')) {
|
|
3539
|
+
return;
|
|
3540
|
+
}
|
|
3541
|
+
this.emit('update', {
|
|
3542
|
+
editor: this,
|
|
3543
|
+
transaction,
|
|
3544
|
+
});
|
|
3506
3545
|
}
|
|
3507
|
-
|
|
3508
|
-
|
|
3546
|
+
/**
|
|
3547
|
+
* Get attributes of the currently selected node or mark.
|
|
3548
|
+
*/
|
|
3549
|
+
getAttributes(nameOrType) {
|
|
3550
|
+
return getAttributes(this.state, nameOrType);
|
|
3509
3551
|
}
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3552
|
+
isActive(nameOrAttributes, attributesOrUndefined) {
|
|
3553
|
+
const name = typeof nameOrAttributes === 'string'
|
|
3554
|
+
? nameOrAttributes
|
|
3555
|
+
: null;
|
|
3556
|
+
const attributes = typeof nameOrAttributes === 'string'
|
|
3557
|
+
? attributesOrUndefined
|
|
3558
|
+
: nameOrAttributes;
|
|
3559
|
+
return isActive(this.state, name, attributes);
|
|
3516
3560
|
}
|
|
3517
|
-
|
|
3518
|
-
|
|
3561
|
+
/**
|
|
3562
|
+
* Get the document as JSON.
|
|
3563
|
+
*/
|
|
3564
|
+
getJSON() {
|
|
3565
|
+
return this.state.doc.toJSON();
|
|
3519
3566
|
}
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
// get all inclusive marks on empty selection
|
|
3526
|
-
if (from === to) {
|
|
3527
|
-
doc
|
|
3528
|
-
.resolve(from)
|
|
3529
|
-
.marks()
|
|
3530
|
-
.forEach(mark => {
|
|
3531
|
-
const $pos = doc.resolve(from - 1);
|
|
3532
|
-
const range = getMarkRange($pos, mark.type);
|
|
3533
|
-
if (!range) {
|
|
3534
|
-
return;
|
|
3535
|
-
}
|
|
3536
|
-
marks.push({
|
|
3537
|
-
mark,
|
|
3538
|
-
...range,
|
|
3539
|
-
});
|
|
3540
|
-
});
|
|
3567
|
+
/**
|
|
3568
|
+
* Get the document as HTML.
|
|
3569
|
+
*/
|
|
3570
|
+
getHTML() {
|
|
3571
|
+
return getHTMLFromFragment(this.state.doc.content, this.schema);
|
|
3541
3572
|
}
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3573
|
+
/**
|
|
3574
|
+
* Get the document as text.
|
|
3575
|
+
*/
|
|
3576
|
+
getText(options) {
|
|
3577
|
+
const { blockSeparator = '\n\n', textSerializers = {}, } = options || {};
|
|
3578
|
+
return getText(this.state.doc, {
|
|
3579
|
+
blockSeparator,
|
|
3580
|
+
textSerializers: {
|
|
3581
|
+
...textSerializers,
|
|
3582
|
+
...getTextSerializersFromSchema(this.schema),
|
|
3583
|
+
},
|
|
3549
3584
|
});
|
|
3550
3585
|
}
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
...data,
|
|
3585
|
-
toJSON: () => data,
|
|
3586
|
-
};
|
|
3586
|
+
/**
|
|
3587
|
+
* Check if there is no content.
|
|
3588
|
+
*/
|
|
3589
|
+
get isEmpty() {
|
|
3590
|
+
return isNodeEmpty(this.state.doc);
|
|
3591
|
+
}
|
|
3592
|
+
/**
|
|
3593
|
+
* Get the number of characters for the current document.
|
|
3594
|
+
*
|
|
3595
|
+
* @deprecated
|
|
3596
|
+
*/
|
|
3597
|
+
getCharacterCount() {
|
|
3598
|
+
console.warn('[tiptap warn]: "editor.getCharacterCount()" is deprecated. Please use "editor.storage.characterCount.characters()" instead.');
|
|
3599
|
+
return this.state.doc.content.size - 2;
|
|
3600
|
+
}
|
|
3601
|
+
/**
|
|
3602
|
+
* Destroy the editor.
|
|
3603
|
+
*/
|
|
3604
|
+
destroy() {
|
|
3605
|
+
this.emit('destroy');
|
|
3606
|
+
if (this.view) {
|
|
3607
|
+
this.view.destroy();
|
|
3608
|
+
}
|
|
3609
|
+
this.removeAllListeners();
|
|
3610
|
+
}
|
|
3611
|
+
/**
|
|
3612
|
+
* Check if the editor is already destroyed.
|
|
3613
|
+
*/
|
|
3614
|
+
get isDestroyed() {
|
|
3615
|
+
var _a;
|
|
3616
|
+
// @ts-ignore
|
|
3617
|
+
return !((_a = this.view) === null || _a === void 0 ? void 0 : _a.docView);
|
|
3618
|
+
}
|
|
3587
3619
|
}
|
|
3588
3620
|
|
|
3589
3621
|
/**
|