@openleaf-editor/core 0.1.0-beta.2 → 0.1.0-beta.4
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/README.md +127 -0
- package/dist/autolink.d.ts +7 -4
- package/dist/autolink.d.ts.map +1 -1
- package/dist/autolink.js +90 -11
- package/dist/autolink.js.map +1 -1
- package/dist/command-helpers.d.ts +8 -0
- package/dist/command-helpers.d.ts.map +1 -0
- package/dist/command-helpers.js +36 -0
- package/dist/command-helpers.js.map +1 -0
- package/dist/commands.d.ts +21 -63
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +430 -346
- package/dist/commands.js.map +1 -1
- package/dist/css.d.ts +1 -175
- package/dist/css.d.ts.map +1 -1
- package/dist/css.js +1 -516
- package/dist/css.js.map +1 -1
- package/dist/disclosure.d.ts +21 -0
- package/dist/disclosure.d.ts.map +1 -0
- package/dist/disclosure.js +144 -0
- package/dist/disclosure.js.map +1 -0
- package/dist/elements.d.ts +2 -0
- package/dist/elements.d.ts.map +1 -0
- package/dist/elements.js +2 -0
- package/dist/elements.js.map +1 -0
- package/dist/embed.d.ts +1 -51
- package/dist/embed.d.ts.map +1 -1
- package/dist/embed.js +1 -115
- package/dist/embed.js.map +1 -1
- package/dist/errors.d.ts +38 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +40 -0
- package/dist/errors.js.map +1 -0
- package/dist/extensions.d.ts +46 -5
- package/dist/extensions.d.ts.map +1 -1
- package/dist/extensions.js +272 -52
- package/dist/extensions.js.map +1 -1
- package/dist/figure-drag.d.ts +26 -0
- package/dist/figure-drag.d.ts.map +1 -0
- package/dist/figure-drag.js +75 -0
- package/dist/figure-drag.js.map +1 -0
- package/dist/formats.d.ts.map +1 -1
- package/dist/formats.js +19 -7
- package/dist/formats.js.map +1 -1
- package/dist/gapcursor.d.ts +14 -0
- package/dist/gapcursor.d.ts.map +1 -0
- package/dist/gapcursor.js +17 -0
- package/dist/gapcursor.js.map +1 -0
- package/dist/html.d.ts +32 -2
- package/dist/html.d.ts.map +1 -1
- package/dist/html.js +185 -31
- package/dist/html.js.map +1 -1
- package/dist/index.d.ts +23 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -6
- package/dist/index.js.map +1 -1
- package/dist/insert-commands.d.ts +172 -0
- package/dist/insert-commands.d.ts.map +1 -0
- package/dist/insert-commands.js +560 -0
- package/dist/insert-commands.js.map +1 -0
- package/dist/isolating-selection.d.ts +59 -0
- package/dist/isolating-selection.d.ts.map +1 -0
- package/dist/isolating-selection.js +251 -0
- package/dist/isolating-selection.js.map +1 -0
- package/dist/noneditable.d.ts.map +1 -1
- package/dist/noneditable.js +18 -4
- package/dist/noneditable.js.map +1 -1
- package/dist/plugins.d.ts +20 -2
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +27 -2
- package/dist/plugins.js.map +1 -1
- package/dist/preserve.d.ts +48 -17
- package/dist/preserve.d.ts.map +1 -1
- package/dist/preserve.js +214 -43
- package/dist/preserve.js.map +1 -1
- package/dist/schema.d.ts +15 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +157 -28
- package/dist/schema.js.map +1 -1
- package/dist/structure.d.ts +32 -0
- package/dist/structure.d.ts.map +1 -1
- package/dist/structure.js +53 -10
- package/dist/structure.js.map +1 -1
- package/dist/tables.d.ts +47 -1
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +417 -40
- package/dist/tables.js.map +1 -1
- package/dist/testing.d.ts +3 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +3 -0
- package/dist/testing.js.map +1 -0
- package/dist/tokens.d.ts +8 -0
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +54 -6
- package/dist/tokens.js.map +1 -1
- package/dist/url.d.ts +1 -25
- package/dist/url.d.ts.map +1 -1
- package/dist/url.js +1 -77
- package/dist/url.js.map +1 -1
- package/dist/visual-aids.d.ts +11 -1
- package/dist/visual-aids.d.ts.map +1 -1
- package/dist/visual-aids.js +124 -36
- package/dist/visual-aids.js.map +1 -1
- package/package.json +17 -1
package/dist/css.js
CHANGED
|
@@ -1,517 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* The CSS the schema is willing to model, and nothing else.
|
|
3
|
-
*
|
|
4
|
-
* Alignment and colour are the two formatting features that cannot be expressed
|
|
5
|
-
* as a tag. `<p align="center">` and `<font color="red">` were removed from HTML
|
|
6
|
-
* years ago; every editor this one is meant to replace -- TinyMCE, CKEditor,
|
|
7
|
-
* Google Docs -- writes `style="text-align:center"` and
|
|
8
|
-
* `<span style="color:#c00">` instead. Matching them is not a preference: it is
|
|
9
|
-
* the difference between reading a customer's existing archive and rewriting it.
|
|
10
|
-
*
|
|
11
|
-
* So OpenLeaf emits a `style` attribute, which means it owes a precise answer to
|
|
12
|
-
* "which declarations, with which values". That answer lives here, in one place,
|
|
13
|
-
* because four separate consumers need to agree on it:
|
|
14
|
-
*
|
|
15
|
-
* the schema -- parsing stored HTML and writing it back
|
|
16
|
-
* the commands -- validating what a toolbar hands them
|
|
17
|
-
* the preservation -- deciding whether a `<span style>` is fully modelled and
|
|
18
|
-
* layer can therefore be unwrapped rather than kept as an atom
|
|
19
|
-
* @openleaf-editor/sanitize -- allowing exactly these declarations server-side
|
|
20
|
-
*
|
|
21
|
-
* Four hand-written copies of a CSS allowlist is the same divergence the
|
|
22
|
-
* sanitize package exists to prevent, one layer down.
|
|
23
|
-
*
|
|
24
|
-
* ## Why a validator rather than a blocklist
|
|
25
|
-
*
|
|
26
|
-
* `style` has a genuinely bad history: `expression()` in old IE executed
|
|
27
|
-
* JavaScript, `url()` fetches, `position:fixed` lets pasted content cover the
|
|
28
|
-
* page with something that looks like your UI. None of that is reachable
|
|
29
|
-
* through a closed property allowlist whose values must match a colour, a
|
|
30
|
-
* length, a font name, or one of a few keywords -- and an allowlist stays safe
|
|
31
|
-
* against whatever CSS gains next, which a list of known-bad functions does not.
|
|
32
|
-
*/
|
|
33
|
-
export const ALIGNMENTS = ['left', 'center', 'right', 'justify'];
|
|
34
|
-
/**
|
|
35
|
-
* Declarations the schema models, and therefore the only ones it will write.
|
|
36
|
-
*
|
|
37
|
-
* `@openleaf-editor/sanitize` reads this list to build its own allowlist, so a
|
|
38
|
-
* property added here reaches the server-side policy rather than being stripped
|
|
39
|
-
* from stored content by a policy that never heard of it.
|
|
40
|
-
*/
|
|
41
|
-
export const MODELLED_PROPERTIES = [
|
|
42
|
-
'text-align',
|
|
43
|
-
'color',
|
|
44
|
-
'background-color',
|
|
45
|
-
'font-family',
|
|
46
|
-
'font-size',
|
|
47
|
-
'line-height',
|
|
48
|
-
'padding-inline-start',
|
|
49
|
-
'list-style-type',
|
|
50
|
-
];
|
|
51
|
-
/**
|
|
52
|
-
* The subset a mark can represent, and therefore the subset the preservation
|
|
53
|
-
* layer may unwrap a `<span>` for. Block properties are deliberately absent:
|
|
54
|
-
* unwrapping the element that carries them would drop them.
|
|
55
|
-
*/
|
|
56
|
-
export const COLOUR_PROPERTIES = ['color', 'background-color'];
|
|
57
|
-
export const INLINE_STYLE_PROPERTIES = [
|
|
58
|
-
'color',
|
|
59
|
-
'background-color',
|
|
60
|
-
'font-family',
|
|
61
|
-
'font-size',
|
|
62
|
-
];
|
|
63
|
-
/** Indent step written as `padding-inline-start`. Matches TinyMCE's 2em. */
|
|
64
|
-
export const INDENT_EM = 2;
|
|
65
|
-
export const MAX_INDENT = 8;
|
|
66
|
-
export const LIST_STYLES = [
|
|
67
|
-
'disc',
|
|
68
|
-
'circle',
|
|
69
|
-
'square',
|
|
70
|
-
'decimal',
|
|
71
|
-
'lower-roman',
|
|
72
|
-
'upper-roman',
|
|
73
|
-
'lower-alpha',
|
|
74
|
-
'upper-alpha',
|
|
75
|
-
'lower-greek',
|
|
76
|
-
];
|
|
77
|
-
export const FONT_FAMILIES = [
|
|
78
|
-
'Arial',
|
|
79
|
-
'Georgia',
|
|
80
|
-
'Times New Roman',
|
|
81
|
-
'Courier New',
|
|
82
|
-
'Verdana',
|
|
83
|
-
'Tahoma',
|
|
84
|
-
'Trebuchet MS',
|
|
85
|
-
'Palatino',
|
|
86
|
-
'Garamond',
|
|
87
|
-
'system-ui',
|
|
88
|
-
'serif',
|
|
89
|
-
'sans-serif',
|
|
90
|
-
'monospace',
|
|
91
|
-
];
|
|
92
|
-
/** Preset sizes the toolbar lists, in pixels. The number input accepts any in range. */
|
|
93
|
-
export const FONT_SIZE_PRESETS = [8, 10, 11, 12, 14, 16, 18, 20, 24, 28, 32, 36, 48, 72];
|
|
94
|
-
export const LINE_HEIGHT_PRESETS = ['1', '1.15', '1.5', '2', '2.5'];
|
|
95
|
-
/**
|
|
96
|
-
* Split a `style` attribute into declarations.
|
|
97
|
-
*
|
|
98
|
-
* Deliberately reads the raw attribute rather than the CSSOM. `element.style`
|
|
99
|
-
* normalizes as it parses -- Chrome turns `#ff0000` into `rgb(255, 0, 0)` -- and
|
|
100
|
-
* anything that reads through it rewrites every hex colour in an archive on the
|
|
101
|
-
* first save. The parse is trivial because the values that survive validation
|
|
102
|
-
* contain no semicolons or quotes; anything that does fails validation and is
|
|
103
|
-
* dropped, so a naive split cannot be tricked into producing a value the
|
|
104
|
-
* validators would not have accepted anyway.
|
|
105
|
-
*
|
|
106
|
-
* Keys are lowercased; values keep their case, because a colour may be a hex
|
|
107
|
-
* digit sequence an author wrote in capitals and there is no reason to change it.
|
|
108
|
-
*/
|
|
109
|
-
export function parseDeclarations(style) {
|
|
110
|
-
const out = new Map();
|
|
111
|
-
if (!style)
|
|
112
|
-
return out;
|
|
113
|
-
for (const part of style.split(';')) {
|
|
114
|
-
const colon = part.indexOf(':');
|
|
115
|
-
if (colon < 0)
|
|
116
|
-
continue;
|
|
117
|
-
const name = part.slice(0, colon).trim().toLowerCase();
|
|
118
|
-
const value = part.slice(colon + 1).trim();
|
|
119
|
-
if (name === '' || value === '')
|
|
120
|
-
continue;
|
|
121
|
-
out.set(name, value);
|
|
122
|
-
}
|
|
123
|
-
return out;
|
|
124
|
-
}
|
|
125
|
-
/** Join declarations back into a `style` attribute value, or `null` if empty. */
|
|
126
|
-
export function serializeDeclarations(declarations) {
|
|
127
|
-
if (declarations.size === 0)
|
|
128
|
-
return null;
|
|
129
|
-
return [...declarations].map(([name, value]) => `${name}:${value}`).join(';');
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* The alignment this value means, or null.
|
|
133
|
-
*
|
|
134
|
-
* `start` and `end` are accepted because they are what a bidirectional-aware
|
|
135
|
-
* author writes, and they are resolved against the reading direction rather than
|
|
136
|
-
* dropped: in an RTL document `start` is the right edge. They are NOT preserved
|
|
137
|
-
* as `start`/`end`, which is a real if narrow loss -- an RTL paragraph aligned to
|
|
138
|
-
* `start` comes back as `right`, and stays right if the document's direction
|
|
139
|
-
* later changes. Modelling logical alignment properly means a second attribute
|
|
140
|
-
* and a toolbar that can express it, which is a bigger feature than this one.
|
|
141
|
-
*/
|
|
142
|
-
export function safeAlign(value, dir) {
|
|
143
|
-
if (!value)
|
|
144
|
-
return null;
|
|
145
|
-
const candidate = value.trim().toLowerCase();
|
|
146
|
-
const rtl = (dir ?? '').toLowerCase() === 'rtl';
|
|
147
|
-
if (candidate === 'start')
|
|
148
|
-
return rtl ? 'right' : 'left';
|
|
149
|
-
if (candidate === 'end')
|
|
150
|
-
return rtl ? 'left' : 'right';
|
|
151
|
-
return ALIGNMENTS.includes(candidate) ? candidate : null;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* A colour value, or null when it is not one.
|
|
155
|
-
*
|
|
156
|
-
* The three accepted shapes are hex, the `rgb`/`hsl` function families, and a
|
|
157
|
-
* bare keyword. A keyword is matched as a plain identifier rather than against
|
|
158
|
-
* the 148-name CSS colour list: the list costs most of a kilobyte in a bundle
|
|
159
|
-
* with a hard budget, and an unrecognised identifier is not dangerous -- the
|
|
160
|
-
* browser discards the declaration. Every form that can actually reach outside
|
|
161
|
-
* the declaration needs a character this rejects, `(` for `expression()` and
|
|
162
|
-
* `url()` among them, and both are excluded from the keyword shape.
|
|
163
|
-
*/
|
|
164
|
-
const HEX = /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
|
|
165
|
-
const FUNCTIONAL = /^(?:rgba?|hsla?)\(\s*[0-9a-z\s.,%/+-]+\)$/i;
|
|
166
|
-
const KEYWORD = /^[a-z]{3,24}$/i;
|
|
167
|
-
/** `rgb(255, 0, 0)` and friends, so a fully opaque one can become hex. */
|
|
168
|
-
const RGB_CHANNELS = /^rgba?\(\s*(\d{1,3})\s*[,\s]\s*(\d{1,3})\s*[,\s]\s*(\d{1,3})\s*(?:[,/]\s*(1|1?\.0+|100%)\s*)?\)$/i;
|
|
169
|
-
export function safeColor(value) {
|
|
170
|
-
if (!value)
|
|
171
|
-
return null;
|
|
172
|
-
// Collapsed rather than stripped: `rgb(255 0 0)` needs its separators.
|
|
173
|
-
const candidate = value.trim().replace(/\s+/g, ' ');
|
|
174
|
-
if (candidate === '')
|
|
175
|
-
return null;
|
|
176
|
-
const rgb = RGB_CHANNELS.exec(candidate);
|
|
177
|
-
if (rgb) {
|
|
178
|
-
// Normalized to hex, and this is what keeps a round trip stable rather than
|
|
179
|
-
// merely lossless. ProseMirror matches mark style rules through the CSSOM,
|
|
180
|
-
// which hands us `rgb(255, 0, 0)` for an authored `#ff0000` -- so without
|
|
181
|
-
// this, opening and saving a document would rewrite every hex colour in it
|
|
182
|
-
// into a longer functional form. Folding the other direction instead makes
|
|
183
|
-
// both spellings converge on the shorter one, and the second save is a
|
|
184
|
-
// no-op.
|
|
185
|
-
const channels = [rgb[1], rgb[2], rgb[3]].map((n) => Number.parseInt(n, 10));
|
|
186
|
-
if (channels.every((n) => n <= 255)) {
|
|
187
|
-
return `#${channels.map((n) => n.toString(16).padStart(2, '0')).join('')}`;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
if (HEX.test(candidate))
|
|
191
|
-
return candidate.toLowerCase();
|
|
192
|
-
if (FUNCTIONAL.test(candidate))
|
|
193
|
-
return candidate.toLowerCase();
|
|
194
|
-
if (KEYWORD.test(candidate))
|
|
195
|
-
return candidate.toLowerCase();
|
|
196
|
-
return null;
|
|
197
|
-
}
|
|
198
|
-
export function safeDir(value) {
|
|
199
|
-
if (!value)
|
|
200
|
-
return null;
|
|
201
|
-
const candidate = value.trim().toLowerCase();
|
|
202
|
-
return candidate === 'ltr' || candidate === 'rtl' ? candidate : null;
|
|
203
|
-
}
|
|
204
|
-
const GENERIC_FAMILIES = new Set([
|
|
205
|
-
'serif',
|
|
206
|
-
'sans-serif',
|
|
207
|
-
'monospace',
|
|
208
|
-
'cursive',
|
|
209
|
-
'fantasy',
|
|
210
|
-
'system-ui',
|
|
211
|
-
'ui-sans-serif',
|
|
212
|
-
'ui-serif',
|
|
213
|
-
'ui-monospace',
|
|
214
|
-
'ui-rounded',
|
|
215
|
-
'emoji',
|
|
216
|
-
'math',
|
|
217
|
-
'fangsong',
|
|
218
|
-
]);
|
|
219
|
-
/**
|
|
220
|
-
* A font stack, or null.
|
|
221
|
-
*
|
|
222
|
-
* Names are identifiers or quoted strings of letters, digits, spaces and
|
|
223
|
-
* hyphens. Anything that can reach outside the declaration -- `url()`,
|
|
224
|
-
* `expression()`, `var()`, a quote that does not match -- is refused. A stack
|
|
225
|
-
* is a comma-separated list of those names, capped so a paste cannot dump a
|
|
226
|
-
* novel into the attribute.
|
|
227
|
-
*/
|
|
228
|
-
export function safeFontFamily(value) {
|
|
229
|
-
if (!value)
|
|
230
|
-
return null;
|
|
231
|
-
const raw = value.trim();
|
|
232
|
-
if (raw === '' || raw.length > 160)
|
|
233
|
-
return null;
|
|
234
|
-
if (/url\s*\(|expression|var\s*\(|[@\\<>]/i.test(raw))
|
|
235
|
-
return null;
|
|
236
|
-
const parts = [];
|
|
237
|
-
let current = '';
|
|
238
|
-
let quote = null;
|
|
239
|
-
for (const char of raw) {
|
|
240
|
-
if (quote) {
|
|
241
|
-
if (char === quote)
|
|
242
|
-
quote = null;
|
|
243
|
-
current += char;
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
if (char === '"' || char === "'") {
|
|
247
|
-
quote = char;
|
|
248
|
-
current += char;
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
if (char === ',') {
|
|
252
|
-
parts.push(current);
|
|
253
|
-
current = '';
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
current += char;
|
|
257
|
-
}
|
|
258
|
-
if (quote !== null)
|
|
259
|
-
return null;
|
|
260
|
-
parts.push(current);
|
|
261
|
-
if (parts.length === 0 || parts.length > 6)
|
|
262
|
-
return null;
|
|
263
|
-
const out = [];
|
|
264
|
-
for (const part of parts) {
|
|
265
|
-
const family = oneFontFamily(part);
|
|
266
|
-
if (family === null)
|
|
267
|
-
return null;
|
|
268
|
-
out.push(family);
|
|
269
|
-
}
|
|
270
|
-
return out.join(',');
|
|
271
|
-
}
|
|
272
|
-
function oneFontFamily(part) {
|
|
273
|
-
const trimmed = part.trim();
|
|
274
|
-
if (trimmed === '' || trimmed.length > 64)
|
|
275
|
-
return null;
|
|
276
|
-
const quoted = /^(['"])(.*)\1$/.exec(trimmed);
|
|
277
|
-
// `?.[2]` rather than a ternary: a capture group is `string | undefined` to the
|
|
278
|
-
// type checker even when the match succeeded. `(.*)` matches the empty string,
|
|
279
|
-
// so a quoted empty name still reads as '' and is refused below -- the `??`
|
|
280
|
-
// only fires when there was no match at all.
|
|
281
|
-
const name = quoted?.[2] ?? trimmed;
|
|
282
|
-
if (name === '' || /[^a-zA-Z0-9 \-]/.test(name))
|
|
283
|
-
return null;
|
|
284
|
-
if (!/^[a-zA-Z]/.test(name))
|
|
285
|
-
return null;
|
|
286
|
-
const lower = name.toLowerCase();
|
|
287
|
-
if (GENERIC_FAMILIES.has(lower))
|
|
288
|
-
return lower;
|
|
289
|
-
return /\s/.test(name) ? `"${name}"` : name;
|
|
290
|
-
}
|
|
291
|
-
const FONT_SIZE_KEYWORDS = new Set([
|
|
292
|
-
'xx-small',
|
|
293
|
-
'x-small',
|
|
294
|
-
'small',
|
|
295
|
-
'medium',
|
|
296
|
-
'large',
|
|
297
|
-
'x-large',
|
|
298
|
-
'xx-large',
|
|
299
|
-
'xxx-large',
|
|
300
|
-
]);
|
|
301
|
-
const FONT_SIZE_LENGTH = /^(\d+(?:\.\d+)?)(px|pt|em|rem|%)$/i;
|
|
302
|
-
/**
|
|
303
|
-
* A font size, or null.
|
|
304
|
-
*
|
|
305
|
-
* Keywords and a closed set of length units. Values are clamped so a pasted
|
|
306
|
-
* `font-size: 400px` cannot blow the layout out; the toolbar's number input
|
|
307
|
-
* writes pixels inside the same range.
|
|
308
|
-
*/
|
|
309
|
-
export function safeFontSize(value) {
|
|
310
|
-
if (!value)
|
|
311
|
-
return null;
|
|
312
|
-
const candidate = value.trim().toLowerCase().replace(/\s+/g, '');
|
|
313
|
-
if (FONT_SIZE_KEYWORDS.has(candidate))
|
|
314
|
-
return candidate;
|
|
315
|
-
const match = FONT_SIZE_LENGTH.exec(candidate);
|
|
316
|
-
if (!match)
|
|
317
|
-
return null;
|
|
318
|
-
const amount = Number(match[1]);
|
|
319
|
-
const unit = match[2];
|
|
320
|
-
const min = { px: 8, pt: 6, em: 0.5, rem: 0.5, '%': 50 };
|
|
321
|
-
const max = { px: 96, pt: 72, em: 6, rem: 6, '%': 300 };
|
|
322
|
-
if (!(amount >= min[unit] && amount <= max[unit]))
|
|
323
|
-
return null;
|
|
324
|
-
const rendered = Number.isInteger(amount) ? String(amount) : String(amount);
|
|
325
|
-
return `${rendered}${unit}`;
|
|
326
|
-
}
|
|
327
|
-
const LINE_HEIGHT_LENGTH = /^(\d+(?:\.\d+)?)(px|em|rem|%)?$/i;
|
|
328
|
-
/** A line height: `normal`, a unitless multiplier, or a short length. */
|
|
329
|
-
export function safeLineHeight(value) {
|
|
330
|
-
if (!value)
|
|
331
|
-
return null;
|
|
332
|
-
const candidate = value.trim().toLowerCase().replace(/\s+/g, '');
|
|
333
|
-
if (candidate === 'normal')
|
|
334
|
-
return 'normal';
|
|
335
|
-
const match = LINE_HEIGHT_LENGTH.exec(candidate);
|
|
336
|
-
if (!match)
|
|
337
|
-
return null;
|
|
338
|
-
const amount = Number(match[1]);
|
|
339
|
-
const unit = match[2] ?? '';
|
|
340
|
-
if (unit === '') {
|
|
341
|
-
if (!(amount >= 0.5 && amount <= 4))
|
|
342
|
-
return null;
|
|
343
|
-
return Number.isInteger(amount) ? String(amount) : String(amount);
|
|
344
|
-
}
|
|
345
|
-
if (unit === '%') {
|
|
346
|
-
if (!(amount >= 50 && amount <= 400))
|
|
347
|
-
return null;
|
|
348
|
-
return `${formatNumber(amount)}%`;
|
|
349
|
-
}
|
|
350
|
-
if (!(amount >= 0.5 && amount <= 96))
|
|
351
|
-
return null;
|
|
352
|
-
return `${formatNumber(amount)}${unit}`;
|
|
353
|
-
}
|
|
354
|
-
function formatNumber(amount) {
|
|
355
|
-
return Number.isInteger(amount) ? String(amount) : String(amount);
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* How many indent steps this declaration means, or null.
|
|
359
|
-
*
|
|
360
|
-
* Written as `padding-inline-start: 2em` per step. Inherited `padding-left`
|
|
361
|
-
* and `margin-left` in 40px or 2em multiples are read as the same thing, which
|
|
362
|
-
* is what TinyMCE and CKEditor stored for years.
|
|
363
|
-
*/
|
|
364
|
-
export function indentLevels(value) {
|
|
365
|
-
if (!value)
|
|
366
|
-
return null;
|
|
367
|
-
const candidate = value.trim().toLowerCase().replace(/\s+/g, '');
|
|
368
|
-
const em = /^(\d+(?:\.\d+)?)em$/.exec(candidate);
|
|
369
|
-
if (em)
|
|
370
|
-
return stepsFrom(Number(em[1]), INDENT_EM);
|
|
371
|
-
const px = /^(\d+(?:\.\d+)?)px$/.exec(candidate);
|
|
372
|
-
if (px)
|
|
373
|
-
return stepsFrom(Number(px[1]), 40);
|
|
374
|
-
return null;
|
|
375
|
-
}
|
|
376
|
-
function stepsFrom(amount, step) {
|
|
377
|
-
const steps = amount / step;
|
|
378
|
-
if (steps < 0.9 || steps > MAX_INDENT)
|
|
379
|
-
return null;
|
|
380
|
-
const rounded = Math.round(steps);
|
|
381
|
-
return Math.abs(steps - rounded) < 0.05 ? rounded : null;
|
|
382
|
-
}
|
|
383
|
-
export function indentCss(levels) {
|
|
384
|
-
return `${levels * INDENT_EM}em`;
|
|
385
|
-
}
|
|
386
|
-
const LIST_STYLE_ALIASES = {
|
|
387
|
-
disc: 'disc',
|
|
388
|
-
circle: 'circle',
|
|
389
|
-
square: 'square',
|
|
390
|
-
decimal: 'decimal',
|
|
391
|
-
'lower-roman': 'lower-roman',
|
|
392
|
-
'upper-roman': 'upper-roman',
|
|
393
|
-
'lower-alpha': 'lower-alpha',
|
|
394
|
-
'upper-alpha': 'upper-alpha',
|
|
395
|
-
'lower-latin': 'lower-alpha',
|
|
396
|
-
'upper-latin': 'upper-alpha',
|
|
397
|
-
'lower-greek': 'lower-greek',
|
|
398
|
-
// HTML `type` on <ol>.
|
|
399
|
-
a: 'lower-alpha',
|
|
400
|
-
A: 'upper-alpha',
|
|
401
|
-
i: 'lower-roman',
|
|
402
|
-
I: 'upper-roman',
|
|
403
|
-
'1': 'decimal',
|
|
404
|
-
};
|
|
405
|
-
export function safeListStyle(value) {
|
|
406
|
-
if (!value)
|
|
407
|
-
return null;
|
|
408
|
-
const candidate = value.trim();
|
|
409
|
-
return LIST_STYLE_ALIASES[candidate] ?? LIST_STYLE_ALIASES[candidate.toLowerCase()] ?? null;
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* A BCP 47-shaped language tag, or null.
|
|
413
|
-
*
|
|
414
|
-
* Not a complete parser: it admits `en`, `en-GB`, `zh-Hans-CN` and refuses
|
|
415
|
-
* anything that could not be a language tag. The point is to keep `lang`
|
|
416
|
-
* from becoming a free-form attribute for whatever a paste stuffed in it.
|
|
417
|
-
*/
|
|
418
|
-
export function safeLang(value) {
|
|
419
|
-
if (!value)
|
|
420
|
-
return null;
|
|
421
|
-
const candidate = value.trim();
|
|
422
|
-
if (candidate.length < 2 || candidate.length > 35)
|
|
423
|
-
return null;
|
|
424
|
-
if (!/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{1,8}){0,4}$/.test(candidate))
|
|
425
|
-
return null;
|
|
426
|
-
return candidate;
|
|
427
|
-
}
|
|
428
|
-
/** The canonical value for a modelled declaration, or null if it is not one. */
|
|
429
|
-
export function modelledValue(property, value) {
|
|
430
|
-
switch (property) {
|
|
431
|
-
case 'text-align':
|
|
432
|
-
return safeAlign(value);
|
|
433
|
-
case 'color':
|
|
434
|
-
case 'background-color':
|
|
435
|
-
return safeColor(value);
|
|
436
|
-
case 'font-family':
|
|
437
|
-
return safeFontFamily(value);
|
|
438
|
-
case 'font-size':
|
|
439
|
-
return safeFontSize(value);
|
|
440
|
-
case 'line-height':
|
|
441
|
-
return safeLineHeight(value);
|
|
442
|
-
case 'padding-inline-start':
|
|
443
|
-
case 'padding-left':
|
|
444
|
-
case 'margin-inline-start':
|
|
445
|
-
case 'margin-left': {
|
|
446
|
-
const steps = indentLevels(value);
|
|
447
|
-
return steps === null ? null : indentCss(steps);
|
|
448
|
-
}
|
|
449
|
-
case 'list-style-type':
|
|
450
|
-
return safeListStyle(value);
|
|
451
|
-
default:
|
|
452
|
-
return null;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* Put CSS on an element without losing the author's spelling.
|
|
457
|
-
*
|
|
458
|
-
* ## Why this is not simply `setAttribute('style', css)`
|
|
459
|
-
*
|
|
460
|
-
* ProseMirror's DOM serializer writes `style` with `element.style.cssText = value`,
|
|
461
|
-
* which routes the declaration through the CSSOM -- and the CSSOM rewrites as it
|
|
462
|
-
* parses. `color:#cc0000` comes back out as `color: rgb(204, 0, 0)`. Measured in
|
|
463
|
-
* Chromium and WebKit: `setAttribute` preserves the string exactly, `cssText`
|
|
464
|
-
* does not.
|
|
465
|
-
*
|
|
466
|
-
* The consequence of letting the serializer do it is that opening and saving a
|
|
467
|
-
* document rewrites every hex colour in it into a longer functional form. No
|
|
468
|
-
* information is lost, so it is a normalization rather than a fidelity bug -- but
|
|
469
|
-
* it is a normalization that touches the COMMON case in inherited content, and
|
|
470
|
-
* "we changed every coloured span in your archive" is not a diff this project
|
|
471
|
-
* gets to put in somebody's revision history quietly. So the nodes and marks that
|
|
472
|
-
* emit CSS return a real element and set the attribute themselves.
|
|
473
|
-
*
|
|
474
|
-
* ## Why it then falls back to the CSSOM anyway
|
|
475
|
-
*
|
|
476
|
-
* A strict Content-Security-Policy without `unsafe-inline` in `style-src` blocks
|
|
477
|
-
* a `style` ATTRIBUTE: the attribute stays in the DOM and the browser refuses to
|
|
478
|
-
* parse it, so the paragraph renders unaligned and the console fills with
|
|
479
|
-
* violations. A CSSOM write is not blocked -- the same distinction that makes the
|
|
480
|
-
* toolbar's constructable stylesheet CSP-safe.
|
|
481
|
-
*
|
|
482
|
-
* So: set the attribute, then check whether the browser honoured it, and fall
|
|
483
|
-
* back to `cssText` if it did not. Under an ordinary CSP the author's spelling
|
|
484
|
-
* survives; under a strict one the formatting still renders, at the cost of the
|
|
485
|
-
* normalization. Getting both right in the environment that has both is not
|
|
486
|
-
* possible, and of the two, "it renders" has to win.
|
|
487
|
-
*/
|
|
488
|
-
export function applyStyleAttribute(el, css) {
|
|
489
|
-
el.setAttribute('style', css);
|
|
490
|
-
const style = el.style;
|
|
491
|
-
// `length` is zero when the attribute was set but not parsed, which is exactly
|
|
492
|
-
// the CSP-blocked case. It is also zero if the declaration was invalid, where
|
|
493
|
-
// falling through costs nothing because there was nothing to render.
|
|
494
|
-
if (style && style.length === 0)
|
|
495
|
-
style.cssText = css;
|
|
496
|
-
}
|
|
497
|
-
/**
|
|
498
|
-
* Is every declaration in this `style` attribute one the schema models?
|
|
499
|
-
*
|
|
500
|
-
* The preservation layer asks this before unwrapping a `<span style>`. A span
|
|
501
|
-
* carrying only colour and font is fully representable as marks, so unwrapping
|
|
502
|
-
* it loses nothing and the text inside stays editable. One carrying
|
|
503
|
-
* `letter-spacing` as well is not, and it must stay an opaque preserved atom.
|
|
504
|
-
*/
|
|
505
|
-
export function isFullyModelledStyle(style, properties = INLINE_STYLE_PROPERTIES) {
|
|
506
|
-
const declarations = parseDeclarations(style);
|
|
507
|
-
if (declarations.size === 0)
|
|
508
|
-
return false;
|
|
509
|
-
for (const [name, value] of declarations) {
|
|
510
|
-
if (!properties.includes(name))
|
|
511
|
-
return false;
|
|
512
|
-
if (modelledValue(name, value) === null)
|
|
513
|
-
return false;
|
|
514
|
-
}
|
|
515
|
-
return true;
|
|
516
|
-
}
|
|
1
|
+
export * from '@openleaf-editor/content-policy/css';
|
|
517
2
|
//# sourceMappingURL=css.js.map
|
package/dist/css.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"css.js","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"css.js","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Make `<details>` open and close while editing.
|
|
3
|
+
*
|
|
4
|
+
* Outside a contenteditable the browser toggles a `<details>` when its
|
|
5
|
+
* `<summary>` is clicked, and nothing has to be written for it. Inside one that
|
|
6
|
+
* default action does not happen: the click is spent placing a caret, so the
|
|
7
|
+
* element stays in whatever state it was parsed in.
|
|
8
|
+
*
|
|
9
|
+
* The consequence is worse than a control that does nothing. A `<details>` parsed
|
|
10
|
+
* without `open` renders collapsed, and its contents are then unreachable --
|
|
11
|
+
* there is no gesture that expands it, so an author cannot edit or even read the
|
|
12
|
+
* body of a collapsible section they already have in a document.
|
|
13
|
+
*
|
|
14
|
+
* So the toggle is written by hand, against the node's own `open` attribute
|
|
15
|
+
* rather than the DOM's. That is what makes the state part of the document and
|
|
16
|
+
* therefore part of what round-trips; toggling the element directly would be
|
|
17
|
+
* undone by the next redraw.
|
|
18
|
+
*/
|
|
19
|
+
import { Plugin } from 'prosemirror-state';
|
|
20
|
+
export declare function disclosurePlugin(): Plugin;
|
|
21
|
+
//# sourceMappingURL=disclosure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disclosure.d.ts","sourceRoot":"","sources":["../src/disclosure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,MAAM,EAA4B,MAAM,mBAAmB,CAAA;AAIpE,wBAAgB,gBAAgB,IAAI,MAAM,CA4HzC"}
|