@nerd-bible/wordgard 0.5.3-beta6 → 0.6.2-beta1
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/command.js +11 -10
- package/dist/doc.d.ts +45 -48
- package/dist/doc.js +131 -128
- package/dist/editor.d.ts +190 -104
- package/dist/editor.js +2001 -1616
- package/dist/highlight-code.d.ts +249 -0
- package/dist/highlight-code.js +264 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/phrases.d.ts +3 -2
- package/dist/phrases.js +20 -1
- package/dist/schema.d.ts +37 -1
- package/dist/schema.js +154 -127
- package/dist/set.js +5 -4
- package/dist/state.d.ts +68 -22
- package/dist/state.js +137 -107
- package/dist/table.d.ts +3 -2
- package/dist/table.js +32 -14
- package/package.json +3 -2
package/dist/editor.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { GardState, GardSelection, TextblockMap, BidiSpan, Transaction } from 'wordgard/state';
|
|
2
|
-
import { Attributes, Elt, Node, Leaf, parse, Slice, Plot, serialize, Pos, ChangeSet, ValidationError
|
|
2
|
+
import { Attributes, Elt, Node, Mark, Leaf, parse, Slice, Plot, serialize, Pos, ChangeSet, ValidationError } from 'wordgard/doc';
|
|
3
3
|
import { StyleModule } from 'style-mod';
|
|
4
4
|
import { findClusterBreak } from '@marijn/find-cluster-break';
|
|
5
5
|
import { findAbove, PointSet, RangeSet } from 'wordgard/set';
|
|
6
6
|
import { enter, insertLineBreak, selectAll, undo, redo, killToLineEnd, yankKilled, transposeChars, Command, deleteUnit, deleteWord, deleteToLineEnd, moveByUnit, moveByLine, moveByWord, moveToLineSide, moveToDocSide, moveByPage, moveToTextblockSide, setAlignment, toggleUnderline, toggleEmphasis, toggleStrong, deleteLine, insertText, setDirection, deleteSelection, Menu, findWrappable, wrapBlockRange, autoJoinBlocks } from 'wordgard/command';
|
|
7
|
-
import {
|
|
7
|
+
import { phrases, PhraseSet } from 'wordgard/phrases';
|
|
8
|
+
import cr from 'crelt';
|
|
8
9
|
import { history } from 'wordgard/history';
|
|
9
10
|
|
|
10
11
|
function addUpdated(sections, updated) {
|
|
@@ -62,7 +63,7 @@ function separateChange(changes, fromB, toB) {
|
|
|
62
63
|
let lenI = 0, dLen = 0;
|
|
63
64
|
for (let posB = 0, done = false, i = 0; i < changes.length;) {
|
|
64
65
|
let len = changes[i++], ins = changes[i++], endB = posB + (ins < 0 ? len : ins);
|
|
65
|
-
if (fromB
|
|
66
|
+
if (fromB >= endB || toB <= posB) {
|
|
66
67
|
result.push(len, ins);
|
|
67
68
|
}
|
|
68
69
|
else {
|
|
@@ -211,19 +212,19 @@ const Decoration = /*@__PURE__*/(function (Decoration) {
|
|
|
211
212
|
function shape(type, shape, config) {
|
|
212
213
|
let tp = Node.Type.get(type);
|
|
213
214
|
let shapeFunc = typeof shape == "function"
|
|
214
|
-
? tag =>
|
|
215
|
-
:
|
|
215
|
+
? memo(tag => shape(tag))
|
|
216
|
+
: () => shape;
|
|
216
217
|
let atom = typeof shape == "function" ? config?.atom : !shape.hasContent;
|
|
217
|
-
let ext = tagShape.of({ type: tp, shape:
|
|
218
|
+
let ext = tagShape.of({ type: tp, shape: shapeFunc });
|
|
218
219
|
if (tp.isPlot && atom != null)
|
|
219
220
|
ext = [ext, GardState.isAtom.of([tp, atom])];
|
|
220
221
|
return ext;
|
|
221
222
|
}
|
|
222
223
|
Tag.shape = shape;
|
|
223
224
|
(function (shape_1) {
|
|
224
|
-
function
|
|
225
|
+
function derived(type, shape, config) {
|
|
225
226
|
let tp = Node.Type.get(type);
|
|
226
|
-
let ext = tagShape.
|
|
227
|
+
let ext = tagShape.derive(state => {
|
|
227
228
|
let s = shape(state);
|
|
228
229
|
return { type: tp, shape: typeof s == "function" ? memo(s) : () => s };
|
|
229
230
|
});
|
|
@@ -232,7 +233,7 @@ const Decoration = /*@__PURE__*/(function (Decoration) {
|
|
|
232
233
|
ext = [ext, GardState.isAtom.of([tp, atom])];
|
|
233
234
|
return ext;
|
|
234
235
|
}
|
|
235
|
-
shape_1.
|
|
236
|
+
shape_1.derived = derived;
|
|
236
237
|
})(shape = Tag.shape || (Tag.shape = {}));
|
|
237
238
|
function wrapper(type, wrapper, options) {
|
|
238
239
|
if (!wrapper.hasContent)
|
|
@@ -256,10 +257,10 @@ const Decoration = /*@__PURE__*/(function (Decoration) {
|
|
|
256
257
|
}
|
|
257
258
|
Tag.widget = widget;
|
|
258
259
|
(function (widget_1) {
|
|
259
|
-
function
|
|
260
|
+
function derived(type, place, widget) {
|
|
260
261
|
let tp = Node.Type.get(type);
|
|
261
262
|
let p = getPlace(place);
|
|
262
|
-
return tagWidget.
|
|
263
|
+
return tagWidget.derive(state => {
|
|
263
264
|
let w = widget(state);
|
|
264
265
|
return {
|
|
265
266
|
type: tp,
|
|
@@ -268,7 +269,7 @@ const Decoration = /*@__PURE__*/(function (Decoration) {
|
|
|
268
269
|
};
|
|
269
270
|
});
|
|
270
271
|
}
|
|
271
|
-
widget_1.
|
|
272
|
+
widget_1.derived = derived;
|
|
272
273
|
})(widget = Tag.widget || (Tag.widget = {}));
|
|
273
274
|
function attribute(type, attr, value, options) {
|
|
274
275
|
let tp = Node.Type.get(type);
|
|
@@ -277,6 +278,16 @@ const Decoration = /*@__PURE__*/(function (Decoration) {
|
|
|
277
278
|
}
|
|
278
279
|
Tag.attribute = attribute;
|
|
279
280
|
})(Decoration.Tag || (Decoration.Tag = {}));
|
|
281
|
+
(function (Mark$1) {
|
|
282
|
+
function shape(type, shape) {
|
|
283
|
+
if (type instanceof Mark)
|
|
284
|
+
type = type.type;
|
|
285
|
+
if (type.spanning && !("element" in shape))
|
|
286
|
+
throw new Error("Spanning marks must have an element shape");
|
|
287
|
+
return markShape.of({ type, modified: Mark.Type.define(type.name, { ...type.spec, shape }) });
|
|
288
|
+
}
|
|
289
|
+
Mark$1.shape = shape;
|
|
290
|
+
})(Decoration.Mark || (Decoration.Mark = {}));
|
|
280
291
|
class Point {
|
|
281
292
|
constructor() { }
|
|
282
293
|
static widget(widget, options) {
|
|
@@ -324,10 +335,15 @@ const Decoration = /*@__PURE__*/(function (Decoration) {
|
|
|
324
335
|
}
|
|
325
336
|
Decoration.Range = Range;
|
|
326
337
|
;return Decoration})({});
|
|
327
|
-
const tagShape = /*@__PURE__*/GardState.Facet.define(
|
|
338
|
+
const tagShape = /*@__PURE__*/GardState.Facet.define({
|
|
339
|
+
combine: shapes => new Map(shapes.map(s => [s.type, s.shape]).reverse())
|
|
340
|
+
});
|
|
328
341
|
const tagWrapper = /*@__PURE__*/GardState.Facet.define();
|
|
329
342
|
const tagWidget = /*@__PURE__*/GardState.Facet.define();
|
|
330
343
|
const tagAttribute = /*@__PURE__*/GardState.Facet.define();
|
|
344
|
+
const markShape = /*@__PURE__*/GardState.Facet.define({
|
|
345
|
+
combine: shapes => new Map(shapes.map(s => [s.type, s.modified]).reverse())
|
|
346
|
+
});
|
|
331
347
|
function memo(f) {
|
|
332
348
|
let map = new WeakMap();
|
|
333
349
|
return (arg) => {
|
|
@@ -337,11 +353,12 @@ function memo(f) {
|
|
|
337
353
|
return found;
|
|
338
354
|
};
|
|
339
355
|
}
|
|
340
|
-
function addMarkAttributes(shape, tag) {
|
|
356
|
+
function addMarkAttributes(overrides, shape, tag) {
|
|
341
357
|
let attrs;
|
|
342
358
|
for (let mark of tag.marks) {
|
|
343
|
-
|
|
344
|
-
|
|
359
|
+
let type = overrides.get(mark.type) || mark.type;
|
|
360
|
+
if (type.attribute && (mark.spanning || !tag.isText)) {
|
|
361
|
+
let { get, target } = type.attribute;
|
|
345
362
|
let markAttrs = get(mark.value);
|
|
346
363
|
if (markAttrs.length) {
|
|
347
364
|
if (target && shape instanceof Elt)
|
|
@@ -367,13 +384,15 @@ function applyDeco(shape, deco, tag) {
|
|
|
367
384
|
return shape;
|
|
368
385
|
}
|
|
369
386
|
const baseTagShape = /*@__PURE__*/memo((tag) => {
|
|
370
|
-
return
|
|
371
|
-
: tag.type.shape.create(tag.param), tag);
|
|
387
|
+
return tag.is(Leaf.Text) ? Widget.editableText.of(tag.param) : tag.type.shape.create(tag.param);
|
|
372
388
|
});
|
|
373
|
-
function renderMarks(marks, around) {
|
|
374
|
-
let
|
|
389
|
+
function renderMarks(state, marks, around) {
|
|
390
|
+
let markShapes = state.facet(markShape);
|
|
391
|
+
let result = addMarkAttributes(markShapes, Elt.create("span", Attributes.none, [around]), Leaf.text(around, marks));
|
|
375
392
|
for (let i = marks.length - 1; i >= 0; i--) {
|
|
376
|
-
let mark = marks[i];
|
|
393
|
+
let mark = marks[i], shape = markShapes.get(mark.type);
|
|
394
|
+
if (shape)
|
|
395
|
+
mark = shape.of(mark.value);
|
|
377
396
|
if (mark.type.element)
|
|
378
397
|
result = renderMarkWrapper(mark).fill([result]);
|
|
379
398
|
}
|
|
@@ -494,13 +513,10 @@ function compareDecoSet(setA, setB, cmp) {
|
|
|
494
513
|
if (!setA.has(srcB))
|
|
495
514
|
cmp(null, valB);
|
|
496
515
|
}
|
|
497
|
-
|
|
498
|
-
return stateA.facet(facet) != stateB.facet(facet);
|
|
499
|
-
}
|
|
516
|
+
const globalDecoFacets = [tagShape, tagWidget, tagWrapper, tagAttribute, markShape];
|
|
500
517
|
function findChangedRanges(prevState, prevDeco, state, deco, sections) {
|
|
501
518
|
let result = [];
|
|
502
|
-
let globalChange =
|
|
503
|
-
compareGlobal(prevState, state, tagWrapper) || compareGlobal(prevState, state, tagAttribute);
|
|
519
|
+
let globalChange = globalDecoFacets.some(facet => prevState.facet(facet) !== state.facet(facet));
|
|
504
520
|
let shapeChanges = [];
|
|
505
521
|
for (let i = 0, posA = 0, posB = 0; i < sections.length;) {
|
|
506
522
|
let len = sections[i++], ins = sections[i++];
|
|
@@ -652,24 +668,6 @@ class SpanIterator {
|
|
|
652
668
|
return this;
|
|
653
669
|
}
|
|
654
670
|
}
|
|
655
|
-
function nodeWrappers(schema, tag, active, atom) {
|
|
656
|
-
let wrappers;
|
|
657
|
-
for (let mark of tag.marks)
|
|
658
|
-
if (mark.type.element)
|
|
659
|
-
(wrappers || (wrappers = [])).push(mark);
|
|
660
|
-
if (active.length) {
|
|
661
|
-
for (let val of active) {
|
|
662
|
-
if (val instanceof WrapperRangeDecoration && (tagScope(tag, atom) & val.scope) &&
|
|
663
|
-
(!val.query || schema.matchNode(tag.type, val.query)))
|
|
664
|
-
(wrappers || (wrappers = [])).push(val);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
if (!wrappers)
|
|
668
|
-
return none;
|
|
669
|
-
if (wrappers.length > 1)
|
|
670
|
-
wrappers.sort((a, b) => (a.spanning == b.spanning ? 0 : a.spanning ? -1 : 1) || a.rank - b.rank);
|
|
671
|
-
return wrappers;
|
|
672
|
-
}
|
|
673
671
|
function tagScope(tag, atom) {
|
|
674
672
|
return 4 |
|
|
675
673
|
(atom ? 1 | (tag.type.isInline ? 2 : 0) : 0);
|
|
@@ -690,6 +688,7 @@ class DecoIterator {
|
|
|
690
688
|
globalWidgets;
|
|
691
689
|
globalWrappers;
|
|
692
690
|
globalAttrs;
|
|
691
|
+
markShapes;
|
|
693
692
|
schema;
|
|
694
693
|
pos;
|
|
695
694
|
rangeCursor;
|
|
@@ -705,6 +704,7 @@ class DecoIterator {
|
|
|
705
704
|
.some(w => (w.place == 1 || w.place == 3) && typeof w.widget == "function");
|
|
706
705
|
this.globalWrappers = state.facet(tagWrapper);
|
|
707
706
|
this.globalAttrs = state.facet(tagAttribute);
|
|
707
|
+
this.markShapes = state.facet(markShape);
|
|
708
708
|
this.pos = state.doc.resolve(0);
|
|
709
709
|
this.schema = state.schema;
|
|
710
710
|
this.rangeCursor = RangeSet.cursor(state.facet(Decoration.Range.source).map(s => s(state)));
|
|
@@ -729,6 +729,26 @@ class DecoIterator {
|
|
|
729
729
|
(tw.place == 3 || tw.place == 1) &&
|
|
730
730
|
typeof tw.widget == "function");
|
|
731
731
|
}
|
|
732
|
+
nodeWrappers(tag, active, atom) {
|
|
733
|
+
let wrappers;
|
|
734
|
+
for (let mark of tag.marks) {
|
|
735
|
+
let shape = this.markShapes.get(mark.type) || mark.type;
|
|
736
|
+
if (shape.element)
|
|
737
|
+
(wrappers || (wrappers = [])).push(shape == mark.type ? mark : shape.of(mark.value));
|
|
738
|
+
}
|
|
739
|
+
if (active.length) {
|
|
740
|
+
for (let val of active) {
|
|
741
|
+
if (val instanceof WrapperRangeDecoration && (tagScope(tag, atom) & val.scope) &&
|
|
742
|
+
(!val.query || this.schema.matchNode(tag.type, val.query)))
|
|
743
|
+
(wrappers || (wrappers = [])).push(val);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
if (!wrappers)
|
|
747
|
+
return none;
|
|
748
|
+
if (wrappers.length > 1)
|
|
749
|
+
wrappers.sort((a, b) => (a.spanning == b.spanning ? 0 : a.spanning ? -1 : 1) || a.rank - b.rank);
|
|
750
|
+
return wrappers;
|
|
751
|
+
}
|
|
732
752
|
walk(from, inclusiveStart, to, walker) {
|
|
733
753
|
this.rangeCursor.goto(from);
|
|
734
754
|
this.pointCursor.goto(from, inclusiveStart ? -1e9 : 1000000000);
|
|
@@ -753,7 +773,7 @@ class DecoIterator {
|
|
|
753
773
|
shape = applyDeco(shape, deco, node.tag);
|
|
754
774
|
if (shape.hasContent)
|
|
755
775
|
throw new Error("Leaf nodes shapes shouldn't have a content hole");
|
|
756
|
-
walker.node(node, shape, nodeWrappers(
|
|
776
|
+
walker.node(node, shape, this.nodeWrappers(node.tag, iter.active, true), undefined);
|
|
757
777
|
this.widgets(node.tag, 1, walker);
|
|
758
778
|
},
|
|
759
779
|
enterPlot: (node, pos) => {
|
|
@@ -766,7 +786,7 @@ class DecoIterator {
|
|
|
766
786
|
if (pendingPos == pos)
|
|
767
787
|
for (let deco of pendingDeco)
|
|
768
788
|
shape = applyDeco(shape, deco, node.tag);
|
|
769
|
-
let wrappers = nodeWrappers(
|
|
789
|
+
let wrappers = this.nodeWrappers(node.tag, iter.active, !shape.hasContent);
|
|
770
790
|
let atom = !shape.hasContent;
|
|
771
791
|
if (atom)
|
|
772
792
|
walker.node(node, shape, wrappers, pos + node.length > to ? to - pos : undefined);
|
|
@@ -842,15 +862,10 @@ class DecoIterator {
|
|
|
842
862
|
this.pos = pos;
|
|
843
863
|
}
|
|
844
864
|
tagShape(tag, active) {
|
|
845
|
-
let
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
shape = src.shape(tag);
|
|
850
|
-
break;
|
|
851
|
-
}
|
|
852
|
-
if (!shape)
|
|
853
|
-
shape = baseTagShape(tag);
|
|
865
|
+
let override = this.tagShapes.get(tag.type);
|
|
866
|
+
let shape = override ? override(tag) : baseTagShape(tag);
|
|
867
|
+
if (tag.marks.length)
|
|
868
|
+
shape = addMarkAttributes(this.markShapes, shape, tag);
|
|
854
869
|
let add;
|
|
855
870
|
for (let src of this.globalAttrs)
|
|
856
871
|
if (tag.type == src.type) {
|
|
@@ -1423,6 +1438,13 @@ class CompositeTile extends Tile {
|
|
|
1423
1438
|
return null;
|
|
1424
1439
|
let { closest, rect } = result;
|
|
1425
1440
|
let pos = this.posBeforeChild(closest, start);
|
|
1441
|
+
if (textblock && textblock.start == start && (x < rect.left || x > rect.right)) {
|
|
1442
|
+
let start = (x < rect.left) == textblock.ltr;
|
|
1443
|
+
let span = start ? textblock.order[0] : textblock.order[textblock.order.length - 1];
|
|
1444
|
+
if (span.ltr != textblock.ltr && pos >= span.from + textblock.start && pos <= span.to + textblock.start)
|
|
1445
|
+
return start ? CoordPos.create(textblock.start, -1)
|
|
1446
|
+
: CoordPos.create(textblock.start + textblock.node.contentLength, 1);
|
|
1447
|
+
}
|
|
1426
1448
|
if (closest.dom.nodeName == "BR")
|
|
1427
1449
|
return CoordPos.create(pos, 1);
|
|
1428
1450
|
if (closest.tag && closest.tag.isPlot && closest.tag.type.isInline) {
|
|
@@ -1529,6 +1551,8 @@ class DocTile extends CompositeTile {
|
|
|
1529
1551
|
changes = separated;
|
|
1530
1552
|
}
|
|
1531
1553
|
let builder = new ContentUpdate(state, this, wg, new DecoIterator(state, decoSet), wrapper);
|
|
1554
|
+
if (composition?.target && Tile.get(composition.target))
|
|
1555
|
+
builder.reused.set(Tile.get(composition.target), 2);
|
|
1532
1556
|
for (let i = 0, posB = 0, startCovered = false; i < changes.length;) {
|
|
1533
1557
|
let len = changes[i++], ins = changes[i++];
|
|
1534
1558
|
if (composition && posB == composition.fromB && ins >= 0) {
|
|
@@ -1947,7 +1971,7 @@ class TilePointer {
|
|
|
1947
1971
|
}
|
|
1948
1972
|
tileAfter() {
|
|
1949
1973
|
let { tile, index } = this;
|
|
1950
|
-
if (tile.
|
|
1974
|
+
if (tile.isAtom)
|
|
1951
1975
|
return tile;
|
|
1952
1976
|
return index < tile.children.length ? tile.children[index] : null;
|
|
1953
1977
|
}
|
|
@@ -1973,25 +1997,26 @@ class TilePointer {
|
|
|
1973
1997
|
}
|
|
1974
1998
|
matchingWidget(widget, sideFlag, reused) {
|
|
1975
1999
|
let { index, tile, parent } = this;
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
if (!
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
(before
|
|
1990
|
-
|
|
1991
|
-
|
|
2000
|
+
if (!tile.isAtom)
|
|
2001
|
+
for (;;) {
|
|
2002
|
+
if (!index) {
|
|
2003
|
+
if (!parent || (tile instanceof EltTile ? tile.tag : !(tile instanceof TextTile)))
|
|
2004
|
+
break;
|
|
2005
|
+
({ index, tile, parent } = parent);
|
|
2006
|
+
}
|
|
2007
|
+
else {
|
|
2008
|
+
if (tile instanceof TextTile)
|
|
2009
|
+
break;
|
|
2010
|
+
let before = tile.children[--index];
|
|
2011
|
+
if (!before.isPoint)
|
|
2012
|
+
break;
|
|
2013
|
+
if (!reused.has(before) && before instanceof WidgetTile && before.widget.eq(widget) &&
|
|
2014
|
+
(before.flags & 96) == sideFlag && !(before.flags & 8192)) {
|
|
2015
|
+
reused.set(before, 1);
|
|
2016
|
+
return before;
|
|
2017
|
+
}
|
|
1992
2018
|
}
|
|
1993
2019
|
}
|
|
1994
|
-
}
|
|
1995
2020
|
return null;
|
|
1996
2021
|
}
|
|
1997
2022
|
}
|
|
@@ -2091,7 +2116,7 @@ class ContentUpdate {
|
|
|
2091
2116
|
let cut = [], end = this.posB + len;
|
|
2092
2117
|
if (this.deco.endWidgets)
|
|
2093
2118
|
for (let nw = this.new, { tile, index, parent } = this.old, pos = this.posB; pos < end;) {
|
|
2094
|
-
if (tile
|
|
2119
|
+
if (tile.isAtom) {
|
|
2095
2120
|
pos += tile.length - index;
|
|
2096
2121
|
({ tile, index, parent } = parent);
|
|
2097
2122
|
index++;
|
|
@@ -2541,6 +2566,16 @@ class Coords {
|
|
|
2541
2566
|
}
|
|
2542
2567
|
}
|
|
2543
2568
|
function coordsAtPos(wg, pos, assoc) {
|
|
2569
|
+
let textblock = wg.state.doc.resolve(pos).textblockParent;
|
|
2570
|
+
let map = textblock ? wg.state.textblockMap(textblock) : null;
|
|
2571
|
+
if (textblock && textblock.node.contentLength &&
|
|
2572
|
+
(pos == textblock.start && assoc < 0 || pos == textblock.end && assoc > 0)) {
|
|
2573
|
+
let span = map.order[pos == textblock.start ? 0 : map.order.length - 1];
|
|
2574
|
+
if (span.ltr != map.ltr)
|
|
2575
|
+
pos = textblock.start + (pos == textblock.start ? span.to : span.from);
|
|
2576
|
+
else
|
|
2577
|
+
assoc = -assoc;
|
|
2578
|
+
}
|
|
2544
2579
|
let { offset, tile, pos: tilePos } = wg.docTile.resolve(pos, assoc);
|
|
2545
2580
|
if (tile instanceof TextTile) {
|
|
2546
2581
|
let from = offset, to = offset;
|
|
@@ -2549,7 +2584,7 @@ function coordsAtPos(wg, pos, assoc) {
|
|
|
2549
2584
|
to++;
|
|
2550
2585
|
else
|
|
2551
2586
|
from--;
|
|
2552
|
-
return new Coords(tile, flattenV(singleRect(textRange(tile.dom, from, to), side, true), (side < 0) == ltrAt(wg.state, pos, assoc)));
|
|
2587
|
+
return new Coords(tile, flattenV(singleRect(textRange(tile.dom, from, to), side, true), (side < 0) == ltrAt(wg.state, pos, assoc, map)));
|
|
2553
2588
|
}
|
|
2554
2589
|
let tagTile = tile;
|
|
2555
2590
|
while (!tagTile.tag)
|
|
@@ -2560,7 +2595,7 @@ function coordsAtPos(wg, pos, assoc) {
|
|
|
2560
2595
|
if (tile.widget.type.inFlow) {
|
|
2561
2596
|
let rect = singleRect(tile.dom, after ? 1 : -1);
|
|
2562
2597
|
if (rect.width || rect.height)
|
|
2563
|
-
return new Coords(tile, horizontal ? flattenH(rect, !after) : flattenV(rect, ltrAt(wg.state, pos, 1) == !after));
|
|
2598
|
+
return new Coords(tile, horizontal ? flattenH(rect, !after) : flattenV(rect, ltrAt(wg.state, pos, 1, map) == !after));
|
|
2564
2599
|
}
|
|
2565
2600
|
if (!tile.parent)
|
|
2566
2601
|
return new Coords(tile, new DOMRect);
|
|
@@ -2577,7 +2612,7 @@ function coordsAtPos(wg, pos, assoc) {
|
|
|
2577
2612
|
break;
|
|
2578
2613
|
let rect = singleRect(before.dom, 1);
|
|
2579
2614
|
if (rect.width || rect.height)
|
|
2580
|
-
return new Coords(before, horizontal ? flattenH(rect, false) : flattenV(rect, !ltrAt(wg.state, pos, 1)));
|
|
2615
|
+
return new Coords(before, horizontal ? flattenH(rect, false) : flattenV(rect, !ltrAt(wg.state, pos, 1, map)));
|
|
2581
2616
|
}
|
|
2582
2617
|
}
|
|
2583
2618
|
else { for (let i = offset; i < tile.children.length; i++) {
|
|
@@ -2586,7 +2621,7 @@ function coordsAtPos(wg, pos, assoc) {
|
|
|
2586
2621
|
continue;
|
|
2587
2622
|
let rect = singleRect(after.dom, -1);
|
|
2588
2623
|
if (rect.width || rect.height)
|
|
2589
|
-
return new Coords(after, horizontal ? flattenH(rect, true) : flattenV(rect, ltrAt(wg.state, pos, 1)));
|
|
2624
|
+
return new Coords(after, horizontal ? flattenH(rect, true) : flattenV(rect, ltrAt(wg.state, pos, 1, map)));
|
|
2590
2625
|
}
|
|
2591
2626
|
}
|
|
2592
2627
|
}
|
|
@@ -2630,19 +2665,18 @@ const clipboardInputFilter = /*@__PURE__*/GardState.Facet.define();
|
|
|
2630
2665
|
const clipboardInputHTMLFilter = /*@__PURE__*/GardState.Facet.define();
|
|
2631
2666
|
const clipboardTextParser = /*@__PURE__*/GardState.Facet.define();
|
|
2632
2667
|
const clipboardInputTextFilter = /*@__PURE__*/GardState.Facet.define();
|
|
2633
|
-
function writeClipboard(state, slice,
|
|
2668
|
+
function writeClipboard(state, slice, data) {
|
|
2634
2669
|
for (let filter of state.facet(clipboardOutputFilter))
|
|
2635
2670
|
slice = filter(slice, state);
|
|
2636
2671
|
let includeContext = 0;
|
|
2637
|
-
for (let i = 0; i < context.length; i++) {
|
|
2638
|
-
let next = context[i];
|
|
2639
|
-
if (next.type.defining && (!includeContext || next.type != context[includeContext - 1].type))
|
|
2672
|
+
for (let i = 0; i < slice.context.length; i++) {
|
|
2673
|
+
let next = slice.context[i];
|
|
2674
|
+
if (next.type.defining && (!includeContext || next.type != slice.context[includeContext - 1].type))
|
|
2640
2675
|
includeContext = i + 1;
|
|
2641
2676
|
else if (next.type.defining || !next.isTextblock)
|
|
2642
2677
|
break;
|
|
2643
2678
|
}
|
|
2644
2679
|
let doc = detachedDoc(), dom = serialize.slice(slice, {
|
|
2645
|
-
context,
|
|
2646
2680
|
includeContext,
|
|
2647
2681
|
openAttr: "wg-open"
|
|
2648
2682
|
}).toDOM();
|
|
@@ -2666,7 +2700,7 @@ function writeClipboard(state, slice, context, data) {
|
|
|
2666
2700
|
data.setData("text/html", html);
|
|
2667
2701
|
let text;
|
|
2668
2702
|
for (let serialize of state.facet(clipboardTextSerializer)) {
|
|
2669
|
-
if ((text = serialize(slice,
|
|
2703
|
+
if ((text = serialize(slice, state)) != null)
|
|
2670
2704
|
break;
|
|
2671
2705
|
}
|
|
2672
2706
|
if (text == null)
|
|
@@ -2681,7 +2715,7 @@ function isOpen(elt) {
|
|
|
2681
2715
|
function readClipboard(state, data, targetContext, plain) {
|
|
2682
2716
|
let html = data.getData("text/html");
|
|
2683
2717
|
let text = data.getData("text/plain") || data.getData("Text") || data.getData("text/uri-list").replace(/\r?\n/g, " ");
|
|
2684
|
-
let slice
|
|
2718
|
+
let slice;
|
|
2685
2719
|
if (text && (targetContext.parent.node.type.hasRole(Node.Role.Code) || !html || plain)) {
|
|
2686
2720
|
for (let filter of state.facet(clipboardInputTextFilter))
|
|
2687
2721
|
text = filter(text, state);
|
|
@@ -2697,14 +2731,14 @@ function readClipboard(state, data, targetContext, plain) {
|
|
|
2697
2731
|
if (browser.webkit)
|
|
2698
2732
|
restoreReplacedSpaces(dom);
|
|
2699
2733
|
let fromWordgard = dom.querySelector("[wg-content=true]");
|
|
2700
|
-
|
|
2734
|
+
slice = parse.slice(state.schema, dom, {
|
|
2701
2735
|
collapseWhiteSpace: !fromWordgard,
|
|
2702
2736
|
isOpen: fromWordgard ? isOpen : undefined
|
|
2703
|
-
})
|
|
2737
|
+
});
|
|
2704
2738
|
}
|
|
2705
2739
|
for (let filter of state.facet(clipboardInputFilter))
|
|
2706
2740
|
slice = filter(slice, state);
|
|
2707
|
-
return
|
|
2741
|
+
return slice;
|
|
2708
2742
|
}
|
|
2709
2743
|
function readClipboardText(state, text, context, plain) {
|
|
2710
2744
|
if (!plain)
|
|
@@ -2837,7 +2871,6 @@ const baseStyles = /*@__PURE__*/buildTheme("." + styleID, {
|
|
|
2837
2871
|
whiteSpace: "pre-wrap",
|
|
2838
2872
|
overflowWrap: "anywhere",
|
|
2839
2873
|
wordBreak: "break-word", boxSizing: "border-box",
|
|
2840
|
-
minHeight: "100%",
|
|
2841
2874
|
padding: "4px 12px",
|
|
2842
2875
|
outline: "none",
|
|
2843
2876
|
caretColor: "transparent",
|
|
@@ -2922,14 +2955,26 @@ const baseStyles = /*@__PURE__*/buildTheme("." + styleID, {
|
|
|
2922
2955
|
},
|
|
2923
2956
|
".wg-panels-top": { top: "0" },
|
|
2924
2957
|
".wg-panels-bottom": { bottom: "0" },
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
padding: "
|
|
2928
|
-
|
|
2929
|
-
"
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2958
|
+
dialog: {
|
|
2959
|
+
font: "var(--wg-dialog-font)",
|
|
2960
|
+
padding: "7px 22px 7px 8px",
|
|
2961
|
+
minWidth: "120px",
|
|
2962
|
+
border: "1px solid var(--wg-border-color)",
|
|
2963
|
+
borderRadius: "5px",
|
|
2964
|
+
boxShadow: "0 0 8px 0 rgba(128, 128, 128, 0.2)",
|
|
2965
|
+
inset: "unset",
|
|
2966
|
+
"&.wg-free-dialog": {
|
|
2967
|
+
position: "fixed"
|
|
2968
|
+
}
|
|
2969
|
+
},
|
|
2970
|
+
"h3.wg-dialog-title": {
|
|
2971
|
+
fontSize: "90%",
|
|
2972
|
+
fontWeight: "bold",
|
|
2973
|
+
textAlign: "center",
|
|
2974
|
+
margin: "0 0 0.8em"
|
|
2975
|
+
},
|
|
2976
|
+
"dialog label, dialog .wg-label": {
|
|
2977
|
+
fontSize: "90%"
|
|
2933
2978
|
},
|
|
2934
2979
|
".wg-dialog-close": {
|
|
2935
2980
|
position: "absolute",
|
|
@@ -2959,6 +3004,24 @@ const baseStyles = /*@__PURE__*/buildTheme("." + styleID, {
|
|
|
2959
3004
|
backgroundColor: "#222"
|
|
2960
3005
|
}
|
|
2961
3006
|
},
|
|
3007
|
+
".wg-key-help": {
|
|
3008
|
+
padding: "15px 4px 4px",
|
|
3009
|
+
maxWidth: "350px"
|
|
3010
|
+
},
|
|
3011
|
+
".wg-key-list": {
|
|
3012
|
+
padding: "11px",
|
|
3013
|
+
outline: "none",
|
|
3014
|
+
maxHeight: "calc(min(70vh, 300px))",
|
|
3015
|
+
overflowY: "auto",
|
|
3016
|
+
display: "grid",
|
|
3017
|
+
gridTemplateColumns: "max-content auto",
|
|
3018
|
+
gap: "8px 15px",
|
|
3019
|
+
"& h4": {
|
|
3020
|
+
gridColumn: "span 2",
|
|
3021
|
+
margin: "0.5em 0",
|
|
3022
|
+
fontSize: "110%"
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
2962
3025
|
}, lightDarkIDs);
|
|
2963
3026
|
|
|
2964
3027
|
function setDOMSelection(wg) {
|
|
@@ -3011,7 +3074,7 @@ function rangeForClick(wg, pos, type) {
|
|
|
3011
3074
|
}
|
|
3012
3075
|
else { let cx = wg.state.doc.resolve(pos.pos), block = cx.textblockParent;
|
|
3013
3076
|
if (block)
|
|
3014
|
-
return GardSelection.
|
|
3077
|
+
return GardSelection.undirectionalRange(block.start, block.end);
|
|
3015
3078
|
else
|
|
3016
3079
|
return GardSelection.near(wg.state, pos.pos, pos.side || -1);
|
|
3017
3080
|
}
|
|
@@ -3124,12 +3187,23 @@ function moveToLineBoundary(wg, start, forward) {
|
|
|
3124
3187
|
let startCoords = wg.coordsAtPos(start.head, start.headSide);
|
|
3125
3188
|
let ltr = wg.state.textblockLTR(block.node);
|
|
3126
3189
|
let y = (startCoords.top + startCoords.bottom) / 2, left = forward != ltr;
|
|
3127
|
-
let { pos } = wg.posAtCoords({ x: left ? -1e7 : 1e7, y });
|
|
3190
|
+
let { pos, side } = wg.posAtCoords({ x: left ? -1e7 : 1e7, y });
|
|
3128
3191
|
if (pos < block.start || pos > block.end) {
|
|
3129
3192
|
let blockRect = wg.docTile.nodeTile(block.before).dom.getBoundingClientRect();
|
|
3130
|
-
|
|
3193
|
+
let result = wg.posAtCoords({ x: left ? blockRect.left + 0.2 : blockRect.right - 0.2, y });
|
|
3194
|
+
if (result.pos < block.start) {
|
|
3195
|
+
pos = block.start;
|
|
3196
|
+
side = -1;
|
|
3197
|
+
}
|
|
3198
|
+
else if (result.pos > block.end) {
|
|
3199
|
+
pos = block.end;
|
|
3200
|
+
side = 1;
|
|
3201
|
+
}
|
|
3202
|
+
else {
|
|
3203
|
+
({ pos, side } = result);
|
|
3204
|
+
}
|
|
3131
3205
|
}
|
|
3132
|
-
return GardSelection.cursor(pos,
|
|
3206
|
+
return GardSelection.cursor(pos, side);
|
|
3133
3207
|
}
|
|
3134
3208
|
|
|
3135
3209
|
const observeOptions = {
|
|
@@ -3267,7 +3341,7 @@ class DOMObserver {
|
|
|
3267
3341
|
if (selRange)
|
|
3268
3342
|
range = buildSelectionRangeFromRange(wg, selRange);
|
|
3269
3343
|
}
|
|
3270
|
-
if (!range || this.selectionRange.eq(range))
|
|
3344
|
+
if (!range || !range.focusNode || this.selectionRange.eq(range))
|
|
3271
3345
|
return false;
|
|
3272
3346
|
let context = range.anchorNode && wg.docTile.nearest(range.anchorNode);
|
|
3273
3347
|
if (context instanceof WidgetTile)
|
|
@@ -3279,10 +3353,6 @@ class DOMObserver {
|
|
|
3279
3353
|
this.selectionRange.set(anchor.dom, anchor.offset, head.dom, head.offset);
|
|
3280
3354
|
this.selectionChanged = false;
|
|
3281
3355
|
}
|
|
3282
|
-
clearSelectionRange() {
|
|
3283
|
-
this.selectionRange.set(null, 0, null, 0);
|
|
3284
|
-
this.selectionChanged = false;
|
|
3285
|
-
}
|
|
3286
3356
|
ignore(f) {
|
|
3287
3357
|
let result = f();
|
|
3288
3358
|
this.clear();
|
|
@@ -3376,18 +3446,46 @@ class KeyBinding {
|
|
|
3376
3446
|
static of(spec) { return new KeyBinding(spec); }
|
|
3377
3447
|
}
|
|
3378
3448
|
;KeyBinding = /*@__PURE__*/(function (KeyBinding) {
|
|
3379
|
-
function
|
|
3380
|
-
let map = getKeymap(wg.state
|
|
3381
|
-
return runHandlers(map, event, wg
|
|
3382
|
-
}
|
|
3383
|
-
KeyBinding.
|
|
3384
|
-
KeyBinding.
|
|
3449
|
+
function handle(wg, event) {
|
|
3450
|
+
let map = getKeymap(wg.state);
|
|
3451
|
+
return runHandlers(map, event, wg);
|
|
3452
|
+
}
|
|
3453
|
+
KeyBinding.handle = handle;
|
|
3454
|
+
KeyBinding.keymap = GardState.Field.Derived.define(s => {
|
|
3455
|
+
let bindings = s.facet(KeyBinding.source);
|
|
3456
|
+
return s.facet(KeyBinding.useDefaultKeymap) ? bindings.concat(KeyBinding.defaultKeymap) : bindings;
|
|
3457
|
+
});
|
|
3458
|
+
KeyBinding.source = GardState.Facet.define({
|
|
3459
|
+
enables: KeyBinding.keymap
|
|
3460
|
+
});
|
|
3385
3461
|
KeyBinding.useDefaultKeymap = GardState.Facet.define({
|
|
3386
3462
|
combine: input => input.length ? input[0] : true
|
|
3387
3463
|
});
|
|
3464
|
+
class Group {
|
|
3465
|
+
description;
|
|
3466
|
+
rank;
|
|
3467
|
+
constructor(
|
|
3468
|
+
description,
|
|
3469
|
+
rank) {
|
|
3470
|
+
this.description = description;
|
|
3471
|
+
this.rank = rank;
|
|
3472
|
+
}
|
|
3473
|
+
static define(spec) {
|
|
3474
|
+
return new Group(spec.description, spec.rank || 1000);
|
|
3475
|
+
}
|
|
3476
|
+
static Inline = new Group(phrases.ref("group_inline"), 20);
|
|
3477
|
+
static Block = new Group(phrases.ref("group_block"), 30);
|
|
3478
|
+
static History = new Group(phrases.ref("group_history"), 70);
|
|
3479
|
+
}
|
|
3480
|
+
KeyBinding.Group = Group;
|
|
3481
|
+
function lookupByDescription(state, desc) {
|
|
3482
|
+
return getDescMap(state).get(desc) || null;
|
|
3483
|
+
}
|
|
3484
|
+
KeyBinding.lookupByDescription = lookupByDescription;
|
|
3388
3485
|
KeyBinding.defaultKeymap = [
|
|
3389
3486
|
{ key: "Enter", run: enter },
|
|
3390
|
-
{ key: "Shift-Enter", run: insertLineBreak
|
|
3487
|
+
{ key: "Shift-Enter", run: insertLineBreak,
|
|
3488
|
+
description: phrases.ref("insert_break"), group: Group.Inline },
|
|
3391
3489
|
{ key: "Backspace", run: Command.bind(deleteUnit, "backward") },
|
|
3392
3490
|
{ key: "Delete", run: Command.bind(deleteUnit, "forward") },
|
|
3393
3491
|
{ key: "Ctrl-Backspace", mac: "Alt-Backspace", run: Command.bind(deleteWord, "backward") },
|
|
@@ -3431,9 +3529,9 @@ class KeyBinding {
|
|
|
3431
3529
|
{ key: "Mod-End", run: Command.bind(moveToDocSide, { side: "end" }),
|
|
3432
3530
|
shift: Command.bind(moveToDocSide, { side: "end", extend: true }) },
|
|
3433
3531
|
{ key: "Mod-a", run: selectAll },
|
|
3434
|
-
{ key: "Mod-z", run: undo },
|
|
3435
|
-
{ key: "Mod-y", mac: "Mod-Shift-z", run: redo },
|
|
3436
|
-
{ linux: "Ctrl-Shift-z", run: redo },
|
|
3532
|
+
{ key: "Mod-z", run: undo, description: phrases.ref("undo"), group: Group.History },
|
|
3533
|
+
{ key: "Mod-y", mac: "Mod-Shift-z", run: redo, description: phrases.ref("redo"), group: Group.History },
|
|
3534
|
+
{ linux: "Ctrl-Shift-z", run: redo, description: phrases.ref("redo"), group: Group.History },
|
|
3437
3535
|
{ mac: "Ctrl-b", run: Command.bind(moveByUnit, { dir: "backward" }),
|
|
3438
3536
|
shift: Command.bind(moveByUnit, { dir: "backward", extend: true }) },
|
|
3439
3537
|
{ mac: "Ctrl-f", run: Command.bind(moveByUnit, { dir: "forward" }),
|
|
@@ -3467,15 +3565,15 @@ function normalizeKeyName(name, platform) {
|
|
|
3467
3565
|
let alt, ctrl, shift, meta;
|
|
3468
3566
|
for (let i = 0; i < parts.length - 1; ++i) {
|
|
3469
3567
|
const mod = parts[i];
|
|
3470
|
-
if (
|
|
3568
|
+
if (mod == "Cmd" || mod == "Meta")
|
|
3471
3569
|
meta = true;
|
|
3472
|
-
else if (
|
|
3570
|
+
else if (mod == "Alt")
|
|
3473
3571
|
alt = true;
|
|
3474
|
-
else if (
|
|
3572
|
+
else if (mod == "Ctrl")
|
|
3475
3573
|
ctrl = true;
|
|
3476
|
-
else if (
|
|
3574
|
+
else if (mod == "Shift")
|
|
3477
3575
|
shift = true;
|
|
3478
|
-
else if (
|
|
3576
|
+
else if (mod == "Mod") {
|
|
3479
3577
|
if (platform == "mac")
|
|
3480
3578
|
meta = true;
|
|
3481
3579
|
else
|
|
@@ -3489,18 +3587,18 @@ function normalizeKeyName(name, platform) {
|
|
|
3489
3587
|
if (ctrl)
|
|
3490
3588
|
result = "Ctrl-" + result;
|
|
3491
3589
|
if (meta)
|
|
3492
|
-
result = "Meta-" + result;
|
|
3590
|
+
result = (platform == "mac" ? "Cmd-" : "Meta-") + result;
|
|
3493
3591
|
if (shift)
|
|
3494
3592
|
result = "Shift-" + result;
|
|
3495
3593
|
return result;
|
|
3496
3594
|
}
|
|
3497
|
-
function modifiers(name, event) {
|
|
3595
|
+
function modifiers(name, event, platform) {
|
|
3498
3596
|
if (event.altKey)
|
|
3499
3597
|
name = "Alt-" + name;
|
|
3500
3598
|
if (event.ctrlKey)
|
|
3501
3599
|
name = "Ctrl-" + name;
|
|
3502
3600
|
if (event.metaKey)
|
|
3503
|
-
name = "Meta-" + name;
|
|
3601
|
+
name = (platform == "mac" ? "Cmd-" : "Meta-") + name;
|
|
3504
3602
|
if (event.shiftKey)
|
|
3505
3603
|
name = "Shift-" + name;
|
|
3506
3604
|
return name;
|
|
@@ -3516,56 +3614,65 @@ class NormalizedBinding {
|
|
|
3516
3614
|
}
|
|
3517
3615
|
}
|
|
3518
3616
|
const keymapCache = /*@__PURE__*/(() => new WeakMap())();
|
|
3519
|
-
function getKeymap(
|
|
3617
|
+
function getKeymap(state) {
|
|
3618
|
+
let bindings = state.field(KeyBinding.keymap);
|
|
3520
3619
|
let found = keymapCache.get(bindings);
|
|
3521
|
-
if (!found
|
|
3522
|
-
found =
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3620
|
+
if (!found)
|
|
3621
|
+
keymapCache.set(bindings, found = buildKeymap(bindings, currentPlatform));
|
|
3622
|
+
return found;
|
|
3623
|
+
}
|
|
3624
|
+
const lookupCache = /*@__PURE__*/(() => new WeakMap())();
|
|
3625
|
+
function getDescMap(state) {
|
|
3626
|
+
let bindings = state.field(KeyBinding.keymap);
|
|
3627
|
+
let map = lookupCache.get(bindings);
|
|
3628
|
+
if (!map) {
|
|
3629
|
+
lookupCache.set(bindings, map = new Map);
|
|
3630
|
+
for (let binding of bindings) {
|
|
3631
|
+
let { description, shiftDescription } = binding.spec;
|
|
3632
|
+
if (description || shiftDescription) {
|
|
3633
|
+
let name = binding.spec[currentPlatform] || binding.spec.key;
|
|
3634
|
+
if (name && description)
|
|
3635
|
+
map.set(description, normalizeKeyName(name, currentPlatform));
|
|
3636
|
+
if (name && shiftDescription)
|
|
3637
|
+
map.set(shiftDescription, "Shift-" + normalizeKeyName(name, currentPlatform));
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3527
3640
|
}
|
|
3528
|
-
return
|
|
3641
|
+
return map;
|
|
3529
3642
|
}
|
|
3530
3643
|
function bind(run) {
|
|
3531
3644
|
return (wg) => Command.dispatch(wg, run);
|
|
3532
3645
|
}
|
|
3533
3646
|
function buildKeymap(bindings, platform) {
|
|
3534
|
-
let
|
|
3647
|
+
let map = [];
|
|
3535
3648
|
for (let { spec: b } of bindings) {
|
|
3536
3649
|
let baseFlags = (b.allowDefault ? 8 : 0);
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
let key = b[platform] || b.key;
|
|
3540
|
-
if (b.char) {
|
|
3541
|
-
if (key)
|
|
3542
|
-
throw new Error("A key binding may not provide both a char and a key field");
|
|
3543
|
-
if (b.shift)
|
|
3544
|
-
throw new Error("Shift-modified bindings are not supported for char bindings");
|
|
3545
|
-
array.push(new NormalizedBinding(baseFlags | 1, b.char, bind(b.run)));
|
|
3546
|
-
}
|
|
3650
|
+
let key = b[platform] || b.key;
|
|
3651
|
+
if (b.char) {
|
|
3547
3652
|
if (key)
|
|
3548
|
-
|
|
3549
|
-
if (
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
array.push(new NormalizedBinding(4, "", b.any));
|
|
3653
|
+
throw new Error("A key binding may not provide both a char and a key field");
|
|
3654
|
+
if (b.shift)
|
|
3655
|
+
throw new Error("Shift-modified bindings are not supported for char bindings");
|
|
3656
|
+
map.push(new NormalizedBinding(baseFlags | 1, b.char, bind(b.run)));
|
|
3553
3657
|
}
|
|
3658
|
+
if (key)
|
|
3659
|
+
map.push(new NormalizedBinding(baseFlags | 2, normalizeKeyName(key, platform), bind(b.run)));
|
|
3660
|
+
if (key && b.shift)
|
|
3661
|
+
map.push(new NormalizedBinding(baseFlags | 2, normalizeKeyName("Shift-" + key, platform), bind(b.shift)));
|
|
3662
|
+
if (b.any)
|
|
3663
|
+
map.push(new NormalizedBinding(4, "", b.any));
|
|
3554
3664
|
}
|
|
3555
|
-
return
|
|
3665
|
+
return map;
|
|
3556
3666
|
}
|
|
3557
|
-
function runHandlers(map, event, wg
|
|
3558
|
-
let handlers = map[scope];
|
|
3559
|
-
if (!handlers)
|
|
3560
|
-
return false;
|
|
3667
|
+
function runHandlers(map, event, wg) {
|
|
3561
3668
|
let key = event.key, charCode = key.codePointAt(0);
|
|
3562
3669
|
let altGr = event.getModifierState("AltGraph"), fromCode = charKeyCodes[event.keyCode];
|
|
3563
3670
|
let isChar = codePointSize(charCode) == key.length;
|
|
3564
3671
|
let char = isChar ? String.fromCodePoint(charCode) : null;
|
|
3565
|
-
let base = modifiers(key, event);
|
|
3566
|
-
let fallback = isChar && !altGr && fromCode && fromCode != base ? modifiers(fromCode, event) : null;
|
|
3672
|
+
let base = modifiers(key, event, currentPlatform);
|
|
3673
|
+
let fallback = isChar && !altGr && fromCode && fromCode != base ? modifiers(fromCode, event, currentPlatform) : null;
|
|
3567
3674
|
let handled = false, didMatch = false, allowDefault = false;
|
|
3568
|
-
for (let binding of
|
|
3675
|
+
for (let binding of map) {
|
|
3569
3676
|
let matched = ((binding.flags & 1) && (altGr || !event.ctrlKey && !event.metaKey) && binding.name == char) ||
|
|
3570
3677
|
((binding.flags & 2) && (binding.name == base || binding.name == fallback)) ||
|
|
3571
3678
|
(binding.flags & 4);
|
|
@@ -3612,6 +3719,11 @@ const eventObserver = /*@__PURE__*/GardState.Facet.define({
|
|
|
3612
3719
|
return result;
|
|
3613
3720
|
}
|
|
3614
3721
|
});
|
|
3722
|
+
const compositionInputTypes = /*@__PURE__*/(() => new Set([
|
|
3723
|
+
"insertCompositionText",
|
|
3724
|
+
"deleteCompositionText",
|
|
3725
|
+
"insertFromComposition"
|
|
3726
|
+
]))();
|
|
3615
3727
|
class InputState {
|
|
3616
3728
|
wg;
|
|
3617
3729
|
shiftKey = false;
|
|
@@ -3631,6 +3743,7 @@ class InputState {
|
|
|
3631
3743
|
mouseSelection = null;
|
|
3632
3744
|
draggedContent = null;
|
|
3633
3745
|
notifiedFocused;
|
|
3746
|
+
suppressEvents = false;
|
|
3634
3747
|
pendingInputEvent = null;
|
|
3635
3748
|
domDoc;
|
|
3636
3749
|
_domMapping;
|
|
@@ -3646,6 +3759,8 @@ class InputState {
|
|
|
3646
3759
|
this._domMapping = ChangeSet.empty(this.domDoc.length);
|
|
3647
3760
|
}
|
|
3648
3761
|
handleEvent(event) {
|
|
3762
|
+
if (this.suppressEvents)
|
|
3763
|
+
return;
|
|
3649
3764
|
if (!eventBelongsToEditor(this.wg, event) || this.ignoreDuringComposition(event))
|
|
3650
3765
|
return;
|
|
3651
3766
|
if (event.type == "keydown" && this.keydown(event))
|
|
@@ -3767,11 +3882,12 @@ class InputState {
|
|
|
3767
3882
|
}
|
|
3768
3883
|
}
|
|
3769
3884
|
let command = inputTypeCommands[type];
|
|
3770
|
-
if ((type
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3885
|
+
if (isDeletionInputEvent(type) && range &&
|
|
3886
|
+
(!command ||
|
|
3887
|
+
(range.from != range.to && !this.unflushedSelection && (sel.empty
|
|
3888
|
+
? !isSingleChar(this.domDoc, data.domRange.from, data.domRange.to) ||
|
|
3889
|
+
sel.head != (type == "deleteContentBackward" ? range.to : range.from)
|
|
3890
|
+
: sel.from != range.from || sel.to != range.to)))) {
|
|
3775
3891
|
wg.dispatch({ changes: { from: range.from, to: range.to, fit: true }, userEvent: "delete" });
|
|
3776
3892
|
}
|
|
3777
3893
|
else if (command) {
|
|
@@ -3782,13 +3898,28 @@ class InputState {
|
|
|
3782
3898
|
let { from, to } = this.unflushedSelection ? wg.state.selection : range;
|
|
3783
3899
|
Command.dispatch(wg, insertText, { from, to, insert, userEvent: "input.type" });
|
|
3784
3900
|
}
|
|
3901
|
+
else if (type == "insertFromPaste") {
|
|
3902
|
+
let { from, to } = this.unflushedSelection ? wg.state.selection.replacementRange : range;
|
|
3903
|
+
let slice = readClipboard(wg.state, event.dataTransfer, wg.state.doc.resolve(from), wg.inputState.shiftKey);
|
|
3904
|
+
let isSel = from == wg.state.selection.replacementRange.from && to == wg.state.selection.replacementRange.to;
|
|
3905
|
+
if (isSel && wg.state.facet(pasteHandler).some(h => h(wg, event, slice || Slice.empty)))
|
|
3906
|
+
return;
|
|
3907
|
+
if (slice) {
|
|
3908
|
+
wg.dispatch({
|
|
3909
|
+
changes: { from, to, insert: slice, fit: true },
|
|
3910
|
+
selection: isSel ? (cx, changes) => GardSelection.near(cx, changes.mapPos(to, 1), -1) : undefined,
|
|
3911
|
+
userEvent: "input.paste",
|
|
3912
|
+
scrollIntoView: isSel
|
|
3913
|
+
});
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3785
3916
|
else if ((type == "insertReplacementText" || type == "insertFromYank")) {
|
|
3786
3917
|
let read = readClipboard(wg.state, event.dataTransfer, wg.state.sel.head, true);
|
|
3787
3918
|
let { from, to } = this.unflushedSelection ? wg.state.selection : range;
|
|
3788
3919
|
let sel = wg.state.selection, touchesSel = from <= sel.to && to >= sel.from;
|
|
3789
3920
|
if (read)
|
|
3790
3921
|
wg.dispatch({
|
|
3791
|
-
changes: { from, to, insert: read
|
|
3922
|
+
changes: { from, to, insert: read, fit: true },
|
|
3792
3923
|
selection: touchesSel ? (cx, changes) => {
|
|
3793
3924
|
return GardSelection.near(cx, changes.mapPos(to, 1), -1);
|
|
3794
3925
|
} : undefined,
|
|
@@ -3796,14 +3927,17 @@ class InputState {
|
|
|
3796
3927
|
userEvent: "insert.replacementText"
|
|
3797
3928
|
});
|
|
3798
3929
|
}
|
|
3799
|
-
else if (type
|
|
3800
|
-
let compositionStart =
|
|
3801
|
-
wg.inputState.composing
|
|
3930
|
+
else if (compositionInputTypes.has(type)) {
|
|
3931
|
+
let compositionStart = true;
|
|
3932
|
+
if (wg.inputState.composing) {
|
|
3933
|
+
compositionStart = !wg.inputState.composing.changes;
|
|
3934
|
+
wg.inputState.composing.changes++;
|
|
3935
|
+
}
|
|
3802
3936
|
let sel = wg.observer.selectionRange;
|
|
3803
3937
|
if (!sel.focusNode)
|
|
3804
3938
|
return false;
|
|
3805
3939
|
let userEvent = "input.type.compose" + (compositionStart ? ".start" : "");
|
|
3806
|
-
Command.dispatch(wg, insertText, { from: range.from, to: range.to, insert: event.data, userEvent });
|
|
3940
|
+
Command.dispatch(wg, insertText, { from: range.from, to: range.to, insert: event.data || "", userEvent });
|
|
3807
3941
|
}
|
|
3808
3942
|
else if (type == "formatSetBlockTextDirection") {
|
|
3809
3943
|
if (event.data == "ltr" || event.data == "rtl")
|
|
@@ -3856,6 +3990,58 @@ class InputState {
|
|
|
3856
3990
|
return !tileBefore ? before : !tileAfter ? after : prev == after ? after : before;
|
|
3857
3991
|
}
|
|
3858
3992
|
}
|
|
3993
|
+
getCompositionInfo(wg) {
|
|
3994
|
+
let wrap = this.wrappingComposition;
|
|
3995
|
+
if (wrap) {
|
|
3996
|
+
let sel = wg.state.selection.head;
|
|
3997
|
+
return {
|
|
3998
|
+
fromB: sel, toB: sel,
|
|
3999
|
+
text: "",
|
|
4000
|
+
target: null,
|
|
4001
|
+
wrapCursor: wrap
|
|
4002
|
+
};
|
|
4003
|
+
}
|
|
4004
|
+
let comp = this.composing;
|
|
4005
|
+
if (!comp || !(comp.target = this.findComposition(comp.target)))
|
|
4006
|
+
return null;
|
|
4007
|
+
let value = comp.target.nodeValue;
|
|
4008
|
+
let fromB = this.posAtDOM(comp.target, 0, 1), toB = fromB + value.length;
|
|
4009
|
+
let disrupted = false;
|
|
4010
|
+
this.domMapping.iterChanges((fA, tA, fB, tB) => {
|
|
4011
|
+
if (fB < toB && tB > fromB)
|
|
4012
|
+
disrupted = true;
|
|
4013
|
+
});
|
|
4014
|
+
return disrupted ? null : { fromB, toB, text: value, target: comp.target };
|
|
4015
|
+
}
|
|
4016
|
+
clearComposition() {
|
|
4017
|
+
let comp = this.composing;
|
|
4018
|
+
this.composing = null;
|
|
4019
|
+
this.compositionPendingKey = true;
|
|
4020
|
+
this.compositionEndedAt = Date.now();
|
|
4021
|
+
if (!comp.target)
|
|
4022
|
+
return false;
|
|
4023
|
+
let pos = this.posAtDOM(comp.target, 0, 1);
|
|
4024
|
+
this.wg.observer.addDirtyRange(pos, pos + comp.target.nodeValue.length);
|
|
4025
|
+
return true;
|
|
4026
|
+
}
|
|
4027
|
+
abortComposition() {
|
|
4028
|
+
if (!this.composing || !this.wg.hasFocus)
|
|
4029
|
+
return;
|
|
4030
|
+
this.clearComposition();
|
|
4031
|
+
this.wg.win.setTimeout(() => {
|
|
4032
|
+
this.suppressEvents = true;
|
|
4033
|
+
try {
|
|
4034
|
+
getSelection(this.wg.root)?.collapse(document.body, 0);
|
|
4035
|
+
let dummy = this.wg.win.document.body.appendChild(document.createElement("input"));
|
|
4036
|
+
dummy.focus();
|
|
4037
|
+
dummy.remove();
|
|
4038
|
+
this.wg.focus();
|
|
4039
|
+
}
|
|
4040
|
+
finally {
|
|
4041
|
+
this.suppressEvents = false;
|
|
4042
|
+
}
|
|
4043
|
+
}, 0);
|
|
4044
|
+
}
|
|
3859
4045
|
recordTouch(e) {
|
|
3860
4046
|
this.lastTouchTime = Date.now();
|
|
3861
4047
|
this.lastTouchEvent = e;
|
|
@@ -4072,32 +4258,38 @@ function basicMouseSelection(wg, event) {
|
|
|
4072
4258
|
get(event, extend) {
|
|
4073
4259
|
let cur = queryPos(wg, event), range = rangeForClick(wg, cur, type), { from, to } = range;
|
|
4074
4260
|
if (extend) {
|
|
4261
|
+
let startAnchor = !(startSel instanceof GardSelection.Text) || startSel.directional ? startSel.anchor
|
|
4262
|
+
: from < startSel.from ? startSel.to : startSel.from;
|
|
4075
4263
|
if (from < startSel.anchor)
|
|
4076
|
-
return GardSelection.range(
|
|
4264
|
+
return GardSelection.range(startAnchor, from, from < to ? 1 : cur.side);
|
|
4077
4265
|
else
|
|
4078
|
-
return GardSelection.range(
|
|
4266
|
+
return GardSelection.range(startAnchor, to, from < to ? -1 : cur.side);
|
|
4079
4267
|
}
|
|
4268
|
+
let { anchor, head } = range;
|
|
4080
4269
|
if (start.pos != cur.pos) {
|
|
4081
4270
|
let startRange = rangeForClick(wg, start, type);
|
|
4082
|
-
from = Math.min(
|
|
4083
|
-
|
|
4271
|
+
let from = Math.min(range.from, startRange.from), to = Math.max(range.to, startRange.to);
|
|
4272
|
+
if (startRange.from < range.from) {
|
|
4273
|
+
anchor = from;
|
|
4274
|
+
head = to;
|
|
4275
|
+
}
|
|
4276
|
+
else {
|
|
4277
|
+
anchor = to;
|
|
4278
|
+
head = from;
|
|
4279
|
+
}
|
|
4084
4280
|
}
|
|
4085
|
-
return
|
|
4281
|
+
return anchor == range.anchor && head == range.head ? range
|
|
4282
|
+
: GardSelection.range(anchor, head, head == cur.pos ? cur.side : undefined);
|
|
4086
4283
|
}
|
|
4087
4284
|
};
|
|
4088
4285
|
}
|
|
4089
4286
|
const dropHandler = /*@__PURE__*/GardState.Facet.define();
|
|
4090
4287
|
const pasteHandler = /*@__PURE__*/GardState.Facet.define();
|
|
4091
|
-
function selectionSlice(state) {
|
|
4092
|
-
return {
|
|
4093
|
-
slice: state.doc.slice(state.selection.from, state.selection.to),
|
|
4094
|
-
context: state.doc.contextAt(state.selection.from)
|
|
4095
|
-
};
|
|
4096
|
-
}
|
|
4097
4288
|
function copy(wg, event) {
|
|
4098
4289
|
let { state } = wg;
|
|
4099
|
-
if (!state.selection.empty && event.clipboardData) {
|
|
4100
|
-
|
|
4290
|
+
if (!state.selection.empty && event.clipboardData) {
|
|
4291
|
+
let slice = state.selection.toSlice(state.doc);
|
|
4292
|
+
writeClipboard(state, slice, event.clipboardData);
|
|
4101
4293
|
if (event.type == "cut" && !state.readOnly)
|
|
4102
4294
|
wg.dispatch({
|
|
4103
4295
|
changes: state.selection.ranges.map(r => ({ from: r.from, to: r.to, fit: true })),
|
|
@@ -4118,37 +4310,9 @@ function updateForFocusChange(wg) {
|
|
|
4118
4310
|
}
|
|
4119
4311
|
}, 10);
|
|
4120
4312
|
}
|
|
4121
|
-
function getCompositionInfo(wg) {
|
|
4122
|
-
let wrap = wg.inputState.wrappingComposition;
|
|
4123
|
-
if (wrap) {
|
|
4124
|
-
let sel = wg.state.selection.head;
|
|
4125
|
-
return {
|
|
4126
|
-
fromB: sel, toB: sel,
|
|
4127
|
-
text: "",
|
|
4128
|
-
target: null,
|
|
4129
|
-
wrapCursor: wrap
|
|
4130
|
-
};
|
|
4131
|
-
}
|
|
4132
|
-
let comp = wg.inputState.composing;
|
|
4133
|
-
if (!comp || !(comp.target = wg.inputState.findComposition(comp.target)))
|
|
4134
|
-
return null;
|
|
4135
|
-
let value = comp.target.nodeValue;
|
|
4136
|
-
let pos = wg.inputState.posAtDOM(comp.target, 0);
|
|
4137
|
-
return {
|
|
4138
|
-
fromB: pos, toB: pos + value.length,
|
|
4139
|
-
text: value,
|
|
4140
|
-
target: comp.target
|
|
4141
|
-
};
|
|
4142
|
-
}
|
|
4143
4313
|
function compositionEnd(wg) {
|
|
4144
|
-
|
|
4145
|
-
wg.inputState.composing = null;
|
|
4146
|
-
wg.inputState.compositionEndedAt = Date.now();
|
|
4147
|
-
if (comp && comp.target) {
|
|
4148
|
-
let pos = wg.inputState.posAtDOM(comp.target, 0);
|
|
4149
|
-
wg.observer.addDirtyRange(pos, pos + comp.target.nodeValue.length);
|
|
4314
|
+
if (wg.inputState.composing && wg.inputState.clearComposition())
|
|
4150
4315
|
wg.flush();
|
|
4151
|
-
}
|
|
4152
4316
|
}
|
|
4153
4317
|
function compositionUpdate(wg, event) {
|
|
4154
4318
|
if (!wg.inputState.composing) {
|
|
@@ -4185,7 +4349,7 @@ function inEditableDOM(wg, node) {
|
|
|
4185
4349
|
let tile = wg.docTile.nearest(node);
|
|
4186
4350
|
return tile ? !(tile.isPoint || tile instanceof WidgetTile) : false;
|
|
4187
4351
|
}
|
|
4188
|
-
function isDeletionInputEvent(type) { return /^delete(Content|Word)/.test(type); }
|
|
4352
|
+
function isDeletionInputEvent(type) { return /^delete(Content|Word|ByComposition)/.test(type); }
|
|
4189
4353
|
const inputTypeCommands = /*@__PURE__*/(() => ({
|
|
4190
4354
|
historyUndo: undo,
|
|
4191
4355
|
historyRedo: redo,
|
|
@@ -4218,7 +4382,7 @@ const baseHandlers = {
|
|
|
4218
4382
|
keydown(wg, event) {
|
|
4219
4383
|
if ((browser.ios || browser.android) && (event.key == "Backspace" || event.key == "Enter"))
|
|
4220
4384
|
return false;
|
|
4221
|
-
return KeyBinding.
|
|
4385
|
+
return KeyBinding.handle(wg, event);
|
|
4222
4386
|
},
|
|
4223
4387
|
mousedown(wg, event) {
|
|
4224
4388
|
wg.inputState.shiftKey = event.shiftKey;
|
|
@@ -4257,8 +4421,8 @@ const baseHandlers = {
|
|
|
4257
4421
|
inputState.mouseSelection.dragging = true;
|
|
4258
4422
|
inputState.draggedContent = selection;
|
|
4259
4423
|
if (event.dataTransfer) {
|
|
4260
|
-
let
|
|
4261
|
-
writeClipboard(wg.state, slice,
|
|
4424
|
+
let slice = wg.state.selection.toSlice(wg.state.doc);
|
|
4425
|
+
writeClipboard(wg.state, slice, event.dataTransfer);
|
|
4262
4426
|
event.dataTransfer.effectAllowed = "copyMove";
|
|
4263
4427
|
}
|
|
4264
4428
|
return false;
|
|
@@ -4272,52 +4436,31 @@ const baseHandlers = {
|
|
|
4272
4436
|
drop(wg, event) {
|
|
4273
4437
|
if (!event.dataTransfer || wg.state.readOnly)
|
|
4274
4438
|
return true;
|
|
4275
|
-
let
|
|
4276
|
-
if (!
|
|
4439
|
+
let slice = readClipboard(wg.state, event.dataTransfer, wg.state.sel.head, false);
|
|
4440
|
+
if (!slice)
|
|
4277
4441
|
return false;
|
|
4278
4442
|
let dropPos = wg.posAtCoords({ x: event.clientX, y: event.clientY }).pos;
|
|
4279
4443
|
let { draggedContent } = wg.inputState;
|
|
4280
4444
|
let del = draggedContent && dragMovesSelection(wg, event)
|
|
4281
4445
|
? { from: draggedContent.from, to: draggedContent.to } : null;
|
|
4282
|
-
if (wg.state.facet(dropHandler).some(f => f(wg, event, dropPos, del,
|
|
4446
|
+
if (wg.state.facet(dropHandler).some(f => f(wg, event, dropPos, del, slice)))
|
|
4283
4447
|
return true;
|
|
4284
|
-
let ins = { from: dropPos, insert:
|
|
4448
|
+
let ins = { from: dropPos, insert: slice, fit: true };
|
|
4285
4449
|
let changes = ChangeSet.create(wg.state.doc, del ? [del, ins] : ins);
|
|
4286
4450
|
wg.focus();
|
|
4287
4451
|
wg.dispatch({
|
|
4288
4452
|
changes,
|
|
4289
|
-
selection: GardSelection.
|
|
4453
|
+
selection: GardSelection.undirectionalRange(changes.mapPos(dropPos, -1), changes.mapPos(dropPos, 1)),
|
|
4290
4454
|
userEvent: del ? "move.drop" : "input.drop"
|
|
4291
4455
|
});
|
|
4292
4456
|
wg.inputState.draggedContent = null;
|
|
4293
4457
|
return true;
|
|
4294
4458
|
},
|
|
4295
|
-
paste(wg, event) {
|
|
4296
|
-
if (wg.state.readOnly || !event.clipboardData)
|
|
4297
|
-
return true;
|
|
4298
|
-
let { state } = wg;
|
|
4299
|
-
let content = readClipboard(state, event.clipboardData, state.sel.head, wg.inputState.shiftKey);
|
|
4300
|
-
if (wg.state.facet(pasteHandler).some(h => h(wg, event, content ? content.slice : Slice.empty, content ? content.context : [])))
|
|
4301
|
-
return true;
|
|
4302
|
-
if (content) { wg.dispatch({
|
|
4303
|
-
changes: {
|
|
4304
|
-
from: state.selection.from,
|
|
4305
|
-
to: state.selection.to,
|
|
4306
|
-
insert: content.slice,
|
|
4307
|
-
fit: content.context
|
|
4308
|
-
},
|
|
4309
|
-
selection: (cx, changes) => GardSelection.near(cx, changes.mapPos(state.selection.to, 1), -1),
|
|
4310
|
-
userEvent: "input.paste",
|
|
4311
|
-
scrollIntoView: true
|
|
4312
|
-
});
|
|
4313
|
-
}
|
|
4314
|
-
return true;
|
|
4315
|
-
},
|
|
4316
4459
|
beforeinput(wg, event) {
|
|
4317
4460
|
let type = event.inputType;
|
|
4318
4461
|
if (browser.safari && type == "insertText" && wg.inputState.composing)
|
|
4319
4462
|
compositionEnd(wg);
|
|
4320
|
-
if (type
|
|
4463
|
+
if (compositionInputTypes.has(type) && !wg.inputState.composing)
|
|
4321
4464
|
wg.inputState.composing = { changes: 0, target: null };
|
|
4322
4465
|
let data = {
|
|
4323
4466
|
inputType: type,
|
|
@@ -4333,7 +4476,7 @@ const baseHandlers = {
|
|
|
4333
4476
|
}
|
|
4334
4477
|
wg.inputState.beforeInput(event, wg.inputState.pendingInputEvent = data);
|
|
4335
4478
|
wg.scheduleFlush();
|
|
4336
|
-
let allow = type
|
|
4479
|
+
let allow = compositionInputTypes.has(type) ||
|
|
4337
4480
|
editable && (type == "insertText" || isDeletionInputEvent(type) &&
|
|
4338
4481
|
data.domRange && inlineContext(wg.inputState.domDoc, data.domRange));
|
|
4339
4482
|
return !allow;
|
|
@@ -4344,8 +4487,8 @@ const baseHandlers = {
|
|
|
4344
4487
|
return false;
|
|
4345
4488
|
wg.inputState.pendingInputEvent = null;
|
|
4346
4489
|
let change;
|
|
4347
|
-
if (event.inputType
|
|
4348
|
-
change = { from: pending.domRange.from, to: pending.domRange.to, insert: [Leaf.text(pending.data)] };
|
|
4490
|
+
if (compositionInputTypes.has(event.inputType) || event.inputType == "insertText") {
|
|
4491
|
+
change = { from: pending.domRange.from, to: pending.domRange.to, insert: [Leaf.text(pending.data || "")] };
|
|
4349
4492
|
}
|
|
4350
4493
|
else if (isDeletionInputEvent(event.inputType)) {
|
|
4351
4494
|
change = { from: pending.domRange.from, to: pending.domRange.to };
|
|
@@ -4372,7 +4515,6 @@ const baseObservers = {
|
|
|
4372
4515
|
updateForFocusChange(wg);
|
|
4373
4516
|
},
|
|
4374
4517
|
blur(wg) {
|
|
4375
|
-
wg.observer.clearSelectionRange();
|
|
4376
4518
|
updateForFocusChange(wg);
|
|
4377
4519
|
},
|
|
4378
4520
|
compositionstart: compositionUpdate,
|
|
@@ -4456,15 +4598,18 @@ class ViewState {
|
|
|
4456
4598
|
measure(wg) {
|
|
4457
4599
|
let dom = wg.contentDOM, style = window.getComputedStyle(dom);
|
|
4458
4600
|
this.styleLTR = style.direction == "ltr";
|
|
4459
|
-
let domRect = dom.getBoundingClientRect();
|
|
4460
|
-
this.contentDOMHeight = domRect.height;
|
|
4461
4601
|
let result = 0;
|
|
4602
|
+
let domRect = dom.getBoundingClientRect();
|
|
4603
|
+
if (Math.abs(this.contentDOMHeight - domRect.height) > 0.5) {
|
|
4604
|
+
result |= 2;
|
|
4605
|
+
this.contentDOMHeight = domRect.height;
|
|
4606
|
+
}
|
|
4462
4607
|
if (this.editorWidth != wg.scrollDOM.clientWidth) {
|
|
4463
4608
|
this.editorWidth = wg.scrollDOM.clientWidth;
|
|
4464
4609
|
result |= 2;
|
|
4465
4610
|
}
|
|
4466
4611
|
let contentWidth = domRect.width;
|
|
4467
|
-
if (this.contentDOMWidth
|
|
4612
|
+
if (Math.abs(this.contentDOMWidth - contentWidth) > 0.5 || this.editorHeight != wg.scrollDOM.clientHeight ||
|
|
4468
4613
|
this.editorOffset != wg.scrollDOM.offsetTop) {
|
|
4469
4614
|
this.contentDOMWidth = domRect.width;
|
|
4470
4615
|
this.editorHeight = wg.scrollDOM.clientHeight;
|
|
@@ -4653,7 +4798,7 @@ function getCursorInfo(wg, plugin, cont) {
|
|
|
4653
4798
|
return finish(null);
|
|
4654
4799
|
let target = sel.head.parent.node.isDoc ? wg.contentDOM : wg.nodeDOM(sel.head.parent.before);
|
|
4655
4800
|
wg.scheduleDOMWrite(() => {
|
|
4656
|
-
let temp = renderMarks(marks, "M");
|
|
4801
|
+
let temp = renderMarks(wg.state, marks, "M");
|
|
4657
4802
|
temp.style.position = "absolute";
|
|
4658
4803
|
wg.observer.ignore(() => target.insertBefore(temp, target.firstChild));
|
|
4659
4804
|
wg.scheduleDOMRead(() => {
|
|
@@ -4789,8 +4934,8 @@ class Wordgard {
|
|
|
4789
4934
|
this.lastFlush = Date.now();
|
|
4790
4935
|
try {
|
|
4791
4936
|
let domChanges = this.observer.takeDirty();
|
|
4792
|
-
this.viewState.flush();
|
|
4793
4937
|
this.observer.ignore(() => this.runUpdate(update, domChanges));
|
|
4938
|
+
this.viewState.flush();
|
|
4794
4939
|
domChanges = null;
|
|
4795
4940
|
for (let i = 0;; i++) {
|
|
4796
4941
|
if (i > 5) {
|
|
@@ -4856,7 +5001,9 @@ class Wordgard {
|
|
|
4856
5001
|
scrollRectIntoView(this.scrollDOM, targetRect, assoc, target.spec.x, target.spec.y, Math.max(Math.min(target.spec.xMargin, offsetWidth), -offsetWidth), Math.max(Math.min(target.spec.yMargin, offsetHeight), -offsetHeight), this.state.textLTR);
|
|
4857
5002
|
}
|
|
4858
5003
|
runUpdate(update, domChanges) {
|
|
4859
|
-
let composition = this.composing ? getCompositionInfo(this) : null;
|
|
5004
|
+
let composition = this.composing ? this.inputState.getCompositionInfo(this) : null;
|
|
5005
|
+
if (this.composing && !composition)
|
|
5006
|
+
this.inputState.abortComposition();
|
|
4860
5007
|
let changes = domChanges ? addUpdated(update.changes.sections, domChanges) : update.changes.sections;
|
|
4861
5008
|
let prevDocTile = this.docTile;
|
|
4862
5009
|
if (!update.empty) {
|
|
@@ -5035,7 +5182,7 @@ class Wordgard {
|
|
|
5035
5182
|
if (this.connected)
|
|
5036
5183
|
this.observer.ignore(() => {
|
|
5037
5184
|
this.contentDOM.focus({ preventScroll: true });
|
|
5038
|
-
if (this.willFlush && this.flushing == 0)
|
|
5185
|
+
if (this.willFlush && this.flushing == 0 && this.viewState.pending.some(tr => tr.docChanged))
|
|
5039
5186
|
this.flush();
|
|
5040
5187
|
setDOMSelection(this);
|
|
5041
5188
|
});
|
|
@@ -5365,844 +5512,719 @@ class PluginInstance {
|
|
|
5365
5512
|
}
|
|
5366
5513
|
}
|
|
5367
5514
|
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
if (
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5515
|
+
const Outside = "-10000px";
|
|
5516
|
+
class TooltipViewManager {
|
|
5517
|
+
facet;
|
|
5518
|
+
createTooltipView;
|
|
5519
|
+
removeTooltipView;
|
|
5520
|
+
input;
|
|
5521
|
+
tooltips;
|
|
5522
|
+
tooltipViews;
|
|
5523
|
+
constructor(wg, facet, createTooltipView, removeTooltipView) {
|
|
5524
|
+
this.facet = facet;
|
|
5525
|
+
this.createTooltipView = createTooltipView;
|
|
5526
|
+
this.removeTooltipView = removeTooltipView;
|
|
5527
|
+
this.input = wg.state.facet(facet);
|
|
5528
|
+
this.tooltips = this.input.filter(t => t);
|
|
5529
|
+
let prev = null;
|
|
5530
|
+
this.tooltipViews = this.tooltips.map(t => prev = createTooltipView(t, prev));
|
|
5531
|
+
}
|
|
5532
|
+
update(update, above) {
|
|
5533
|
+
let input = update.state.facet(this.facet);
|
|
5534
|
+
let tooltips = input.filter(x => x);
|
|
5535
|
+
if (input === this.input) {
|
|
5536
|
+
for (let t of this.tooltipViews)
|
|
5537
|
+
if (t.update)
|
|
5538
|
+
t.update(update);
|
|
5539
|
+
return false;
|
|
5540
|
+
}
|
|
5541
|
+
let tooltipViews = [], newAbove = above ? [] : null;
|
|
5542
|
+
for (let i = 0; i < tooltips.length; i++) {
|
|
5543
|
+
let tip = tooltips[i], known = -1;
|
|
5544
|
+
if (!tip)
|
|
5545
|
+
continue;
|
|
5546
|
+
for (let i = 0; i < this.tooltips.length; i++) {
|
|
5547
|
+
let other = this.tooltips[i];
|
|
5548
|
+
if (other && other.create == tip.create)
|
|
5549
|
+
known = i;
|
|
5550
|
+
}
|
|
5551
|
+
if (known < 0) {
|
|
5552
|
+
tooltipViews[i] = this.createTooltipView(tip, i ? tooltipViews[i - 1] : null);
|
|
5553
|
+
if (newAbove)
|
|
5554
|
+
newAbove[i] = !!tip.above;
|
|
5555
|
+
}
|
|
5556
|
+
else {
|
|
5557
|
+
let tooltipView = tooltipViews[i] = this.tooltipViews[known];
|
|
5558
|
+
if (newAbove)
|
|
5559
|
+
newAbove[i] = above[known];
|
|
5560
|
+
if (tooltipView.update)
|
|
5561
|
+
tooltipView.update(update);
|
|
5412
5562
|
}
|
|
5413
|
-
});
|
|
5414
|
-
if (!covered) {
|
|
5415
|
-
let end = tr.startState.doc.resolve(toA);
|
|
5416
|
-
let open = end.matchingParent(p => doc.schema.matchNode(p.type, config.type));
|
|
5417
|
-
if (open && open.before >= fromA)
|
|
5418
|
-
clear.push({ from: open.before, to: open.after });
|
|
5419
5563
|
}
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
let source = (plot, start, add) => points(plot, offset(add, start));
|
|
5431
|
-
let field = GardState.Field.define({
|
|
5432
|
-
create(state) { return init(type, PointSet.create, source, state.doc); },
|
|
5433
|
-
update(value, tr) { return update(config, PointSet.create, source, value, tr); }
|
|
5434
|
-
});
|
|
5435
|
-
result.push(field, Decoration.Point.source.of(s => s.field(field)));
|
|
5436
|
-
}
|
|
5437
|
-
if (ranges) {
|
|
5438
|
-
let source = (plot, start, add) => ranges(plot, offset(add, start));
|
|
5439
|
-
let field = GardState.Field.define({
|
|
5440
|
-
create(state) { return init(type, RangeSet.create, source, state.doc); },
|
|
5441
|
-
update(value, tr) { return update(config, RangeSet.create, source, value, tr); }
|
|
5442
|
-
});
|
|
5443
|
-
result.push(field, Decoration.Range.source.of(s => s.field(field)));
|
|
5444
|
-
}
|
|
5445
|
-
return result;
|
|
5446
|
-
}
|
|
5447
|
-
|
|
5448
|
-
const panelConfig = /*@__PURE__*/GardState.Facet.define({
|
|
5449
|
-
combine(configs) {
|
|
5450
|
-
let topContainer, bottomContainer;
|
|
5451
|
-
for (let c of configs) {
|
|
5452
|
-
topContainer ||= c.topContainer;
|
|
5453
|
-
bottomContainer ||= c.bottomContainer;
|
|
5564
|
+
for (let t of this.tooltipViews)
|
|
5565
|
+
if (tooltipViews.indexOf(t) < 0) {
|
|
5566
|
+
this.removeTooltipView(t);
|
|
5567
|
+
if (update.editor.connected)
|
|
5568
|
+
t.disconnect?.(update.editor);
|
|
5569
|
+
t.remove?.(update.editor);
|
|
5570
|
+
}
|
|
5571
|
+
if (above) {
|
|
5572
|
+
newAbove.forEach((val, i) => above[i] = val);
|
|
5573
|
+
above.length = newAbove.length;
|
|
5454
5574
|
}
|
|
5455
|
-
|
|
5575
|
+
this.input = input;
|
|
5576
|
+
this.tooltips = tooltips;
|
|
5577
|
+
this.tooltipViews = tooltipViews;
|
|
5578
|
+
return true;
|
|
5456
5579
|
}
|
|
5580
|
+
}
|
|
5581
|
+
const tooltipConfig = /*@__PURE__*/GardState.Facet.define({
|
|
5582
|
+
combine: values => ({
|
|
5583
|
+
position: browser.ios ? "absolute" : values.find(conf => conf.position)?.position || "fixed",
|
|
5584
|
+
parent: values.find(conf => conf.parent)?.parent || null,
|
|
5585
|
+
tooltipSpace: values.find(conf => conf.tooltipSpace)?.tooltipSpace || (wg => windowRect(wg.win)),
|
|
5586
|
+
})
|
|
5457
5587
|
});
|
|
5458
|
-
const
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5588
|
+
const knownHeight = /*@__PURE__*/(() => new WeakMap())();
|
|
5589
|
+
const tooltipPlugin = /*@__PURE__*/Wordgard.Plugin.fromClass(class {
|
|
5590
|
+
wg;
|
|
5591
|
+
manager;
|
|
5592
|
+
above = [];
|
|
5593
|
+
inView = true;
|
|
5594
|
+
position;
|
|
5595
|
+
madeAbsolute = false;
|
|
5596
|
+
parent;
|
|
5597
|
+
classes;
|
|
5598
|
+
intersectionObserver;
|
|
5599
|
+
resizeObserver;
|
|
5600
|
+
lastTransaction = 0;
|
|
5601
|
+
measureTimeout = -1;
|
|
5464
5602
|
constructor(wg) {
|
|
5465
|
-
this.
|
|
5466
|
-
|
|
5467
|
-
this.
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
this.
|
|
5472
|
-
this.
|
|
5473
|
-
this.
|
|
5474
|
-
|
|
5603
|
+
this.wg = wg;
|
|
5604
|
+
let config = wg.state.facet(tooltipConfig);
|
|
5605
|
+
this.position = config.position;
|
|
5606
|
+
this.parent = config.parent;
|
|
5607
|
+
this.classes = wg.themeClasses;
|
|
5608
|
+
this.createContainer();
|
|
5609
|
+
this.measure = this.measure.bind(this);
|
|
5610
|
+
this.resizeObserver = typeof ResizeObserver == "function" ? new ResizeObserver(() => this.measureSoon()) : null;
|
|
5611
|
+
this.manager = new TooltipViewManager(wg, Tooltip.show, (t, p) => this.createTooltip(t, p), t => {
|
|
5612
|
+
if (this.resizeObserver)
|
|
5613
|
+
this.resizeObserver.unobserve(t.dom);
|
|
5614
|
+
t.dom.remove();
|
|
5615
|
+
});
|
|
5616
|
+
this.above = this.manager.tooltips.map(t => !!t.above);
|
|
5617
|
+
this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(entries => {
|
|
5618
|
+
if (Date.now() > this.lastTransaction - 50 &&
|
|
5619
|
+
entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1)
|
|
5620
|
+
this.measureSoon();
|
|
5621
|
+
}, { threshold: [1] }) : null;
|
|
5622
|
+
this.observeIntersection();
|
|
5623
|
+
this.maybeMeasure();
|
|
5624
|
+
}
|
|
5625
|
+
createContainer() {
|
|
5626
|
+
if (this.parent) {
|
|
5627
|
+
this.container = document.createElement("wg-tooltip-root");
|
|
5628
|
+
this.container.style.position = "relative";
|
|
5629
|
+
this.container.className = this.wg.themeClasses;
|
|
5630
|
+
this.parent.appendChild(this.container);
|
|
5631
|
+
}
|
|
5632
|
+
else {
|
|
5633
|
+
this.container = this.wg.dom;
|
|
5634
|
+
}
|
|
5635
|
+
}
|
|
5636
|
+
observeIntersection() {
|
|
5637
|
+
if (this.intersectionObserver && this.wg.connected) {
|
|
5638
|
+
this.intersectionObserver.disconnect();
|
|
5639
|
+
for (let tooltip of this.manager.tooltipViews)
|
|
5640
|
+
this.intersectionObserver.observe(tooltip.dom);
|
|
5641
|
+
}
|
|
5642
|
+
}
|
|
5643
|
+
measureSoon() {
|
|
5644
|
+
if (this.measureTimeout < 0)
|
|
5645
|
+
this.measureTimeout = setTimeout(() => {
|
|
5646
|
+
this.measureTimeout = -1;
|
|
5647
|
+
this.maybeMeasure();
|
|
5648
|
+
}, 50);
|
|
5475
5649
|
}
|
|
5476
5650
|
update(update) {
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5651
|
+
if (update.transactions.length)
|
|
5652
|
+
this.lastTransaction = Date.now();
|
|
5653
|
+
let updated = this.manager.update(update, this.above);
|
|
5654
|
+
if (updated)
|
|
5655
|
+
this.observeIntersection();
|
|
5656
|
+
let shouldMeasure = updated || update.geometryChanged;
|
|
5657
|
+
let newConfig = update.state.facet(tooltipConfig);
|
|
5658
|
+
if (newConfig.position != this.position && !this.madeAbsolute) {
|
|
5659
|
+
this.position = newConfig.position;
|
|
5660
|
+
for (let t of this.manager.tooltipViews)
|
|
5661
|
+
t.dom.style.position = this.position;
|
|
5662
|
+
shouldMeasure = true;
|
|
5481
5663
|
}
|
|
5482
|
-
if (
|
|
5483
|
-
this.
|
|
5484
|
-
|
|
5664
|
+
if (newConfig.parent != this.parent) {
|
|
5665
|
+
if (this.parent)
|
|
5666
|
+
this.container.remove();
|
|
5667
|
+
this.parent = newConfig.parent;
|
|
5668
|
+
this.createContainer();
|
|
5669
|
+
for (let t of this.manager.tooltipViews)
|
|
5670
|
+
this.container.appendChild(t.dom);
|
|
5671
|
+
shouldMeasure = true;
|
|
5485
5672
|
}
|
|
5486
|
-
this.
|
|
5487
|
-
|
|
5488
|
-
let input = update.state.facet(Panel.show);
|
|
5489
|
-
if (input != this.input) {
|
|
5490
|
-
let specs = input.filter(x => x);
|
|
5491
|
-
let panels = [], top = [], bottom = [], mount = [];
|
|
5492
|
-
for (let spec of specs) {
|
|
5493
|
-
let known = this.specs.indexOf(spec), panel;
|
|
5494
|
-
if (known < 0) {
|
|
5495
|
-
panel = spec(update.editor);
|
|
5496
|
-
mount.push(panel);
|
|
5497
|
-
}
|
|
5498
|
-
else {
|
|
5499
|
-
panel = this.panels[known];
|
|
5500
|
-
if (panel.update)
|
|
5501
|
-
panel.update(update);
|
|
5502
|
-
}
|
|
5503
|
-
panels.push(panel);
|
|
5504
|
-
(panel.top ? top : bottom).push(panel);
|
|
5505
|
-
}
|
|
5506
|
-
this.specs = specs;
|
|
5507
|
-
this.panels = panels;
|
|
5508
|
-
this.top.sync(top, update.editor);
|
|
5509
|
-
this.bottom.sync(bottom, update.editor);
|
|
5510
|
-
for (let p of mount) {
|
|
5511
|
-
p.dom.classList.add("wg-panel");
|
|
5512
|
-
if (p.connect && update.editor.connected)
|
|
5513
|
-
p.connect(update.editor);
|
|
5514
|
-
}
|
|
5673
|
+
else if (this.parent && this.wg.themeClasses != this.classes) {
|
|
5674
|
+
this.classes = this.container.className = this.wg.themeClasses;
|
|
5515
5675
|
}
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5676
|
+
if (shouldMeasure)
|
|
5677
|
+
this.maybeMeasure();
|
|
5678
|
+
}
|
|
5679
|
+
createTooltip(tooltip, prev) {
|
|
5680
|
+
let tooltipView = tooltip.create(this.wg);
|
|
5681
|
+
let before = prev ? prev.dom : null;
|
|
5682
|
+
tooltipView.dom.classList.add("wg-tooltip");
|
|
5683
|
+
if (tooltip.arrow && !tooltipView.dom.querySelector(".wg-tooltip > wg-tooltip-arrow")) {
|
|
5684
|
+
let arrow = document.createElement("wg-tooltip-arrow");
|
|
5685
|
+
tooltipView.dom.appendChild(arrow);
|
|
5520
5686
|
}
|
|
5687
|
+
tooltipView.dom.style.position = this.position;
|
|
5688
|
+
tooltipView.dom.style.top = Outside;
|
|
5689
|
+
tooltipView.dom.style.left = "0px";
|
|
5690
|
+
this.container.insertBefore(tooltipView.dom, before);
|
|
5691
|
+
if (this.wg.connected)
|
|
5692
|
+
tooltipView.connect?.(this.wg);
|
|
5693
|
+
if (this.resizeObserver && this.wg.connected)
|
|
5694
|
+
this.resizeObserver.observe(tooltipView.dom);
|
|
5695
|
+
return tooltipView;
|
|
5521
5696
|
}
|
|
5522
5697
|
connect(wg) {
|
|
5523
|
-
|
|
5524
|
-
|
|
5698
|
+
wg.win.addEventListener("resize", this.measureSoon = this.measureSoon.bind(this));
|
|
5699
|
+
for (let t of this.manager.tooltipViews) {
|
|
5700
|
+
t.connect?.(wg);
|
|
5701
|
+
if (this.resizeObserver)
|
|
5702
|
+
this.resizeObserver.observe(t.dom);
|
|
5703
|
+
}
|
|
5704
|
+
this.observeIntersection();
|
|
5525
5705
|
}
|
|
5526
5706
|
disconnect(wg) {
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
let value = wg.plugin(plugin);
|
|
5536
|
-
return value && { top: value.top.scrollMargin(), bottom: value.bottom.scrollMargin() };
|
|
5537
|
-
}));
|
|
5538
|
-
const Panel = /*@__PURE__*/(function (Panel) {
|
|
5539
|
-
Panel.show = GardState.Facet.define({
|
|
5540
|
-
enables: panelPlugin
|
|
5541
|
-
});
|
|
5542
|
-
function get(wg, constructor) {
|
|
5543
|
-
let plugin = wg.plugin(panelPlugin);
|
|
5544
|
-
let index = plugin ? plugin.specs.indexOf(constructor) : -1;
|
|
5545
|
-
return index > -1 ? plugin.panels[index] : null;
|
|
5707
|
+
this.wg.win.removeEventListener("resize", this.measureSoon);
|
|
5708
|
+
for (let t of this.manager.tooltipViews) {
|
|
5709
|
+
t.disconnect?.(wg);
|
|
5710
|
+
if (this.resizeObserver)
|
|
5711
|
+
this.resizeObserver.unobserve(t.dom);
|
|
5712
|
+
}
|
|
5713
|
+
if (this.intersectionObserver)
|
|
5714
|
+
this.intersectionObserver.disconnect();
|
|
5546
5715
|
}
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5716
|
+
remove() {
|
|
5717
|
+
for (let tooltipView of this.manager.tooltipViews) {
|
|
5718
|
+
tooltipView.dom.remove();
|
|
5719
|
+
if (this.wg.connected)
|
|
5720
|
+
tooltipView.disconnect?.(this.wg);
|
|
5721
|
+
tooltipView.remove?.(this.wg);
|
|
5722
|
+
}
|
|
5723
|
+
if (this.parent)
|
|
5724
|
+
this.container.remove();
|
|
5725
|
+
clearTimeout(this.measureTimeout);
|
|
5550
5726
|
}
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
wg;
|
|
5555
|
-
top;
|
|
5556
|
-
container;
|
|
5557
|
-
dom = undefined;
|
|
5558
|
-
classes = "";
|
|
5559
|
-
panels = [];
|
|
5560
|
-
constructor(wg, top, container) {
|
|
5561
|
-
this.wg = wg;
|
|
5562
|
-
this.top = top;
|
|
5563
|
-
this.container = container;
|
|
5564
|
-
this.syncClasses();
|
|
5727
|
+
measure() {
|
|
5728
|
+
let measure = this.readMeasure();
|
|
5729
|
+
this.wg.scheduleDOMWrite(() => this.writeMeasure(measure));
|
|
5565
5730
|
}
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5731
|
+
readMeasure() {
|
|
5732
|
+
let scaleX = 1, scaleY = 1, makeAbsolute = false;
|
|
5733
|
+
if (this.position == "fixed" && this.manager.tooltipViews.length) {
|
|
5734
|
+
let { dom } = this.manager.tooltipViews[0];
|
|
5735
|
+
if (browser.safari) {
|
|
5736
|
+
let rect = dom.getBoundingClientRect();
|
|
5737
|
+
makeAbsolute = Math.abs(rect.top + 10000) > 1 || Math.abs(rect.left) > 1;
|
|
5572
5738
|
}
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
}
|
|
5576
|
-
syncDOM() {
|
|
5577
|
-
if (this.panels.length == 0) {
|
|
5578
|
-
if (this.dom) {
|
|
5579
|
-
this.dom.remove();
|
|
5580
|
-
this.dom = undefined;
|
|
5739
|
+
else {
|
|
5740
|
+
makeAbsolute = !!dom.offsetParent && dom.offsetParent != this.container.ownerDocument.body;
|
|
5581
5741
|
}
|
|
5582
|
-
return;
|
|
5583
5742
|
}
|
|
5584
|
-
if (
|
|
5585
|
-
this.
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
}
|
|
5590
|
-
let curDOM = this.dom.firstChild;
|
|
5591
|
-
for (let panel of this.panels) {
|
|
5592
|
-
if (panel.dom.parentNode == this.dom) {
|
|
5593
|
-
while (curDOM != panel.dom)
|
|
5594
|
-
curDOM = rmDOM(curDOM);
|
|
5595
|
-
curDOM = curDOM.nextSibling;
|
|
5596
|
-
}
|
|
5597
|
-
else {
|
|
5598
|
-
this.dom.insertBefore(panel.dom, curDOM);
|
|
5743
|
+
if (makeAbsolute || this.position == "absolute") {
|
|
5744
|
+
let measure = this.parent || this.container, rect = measure.getBoundingClientRect();
|
|
5745
|
+
if (rect.width && rect.height) {
|
|
5746
|
+
scaleX = rect.width / measure.offsetWidth;
|
|
5747
|
+
scaleY = rect.height / measure.offsetHeight;
|
|
5599
5748
|
}
|
|
5600
5749
|
}
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
:
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
if (cls)
|
|
5615
|
-
this.container.classList.remove(cls);
|
|
5616
|
-
for (let cls of (this.classes = this.wg.themeClasses).split(" "))
|
|
5617
|
-
if (cls)
|
|
5618
|
-
this.container.classList.add(cls);
|
|
5619
|
-
}
|
|
5620
|
-
}
|
|
5621
|
-
|
|
5622
|
-
let nextID = 0;
|
|
5623
|
-
function id(prefix) {
|
|
5624
|
-
return prefix + "-" + (nextID++ % 0xffffff).toString(16);
|
|
5625
|
-
}
|
|
5626
|
-
const SVG = "http://www.w3.org/2000/svg";
|
|
5627
|
-
function labelButton(wg, button, label) {
|
|
5628
|
-
button.textContent = "";
|
|
5629
|
-
if (!label) ;
|
|
5630
|
-
else if (typeof label == "function" || typeof label == "string") {
|
|
5631
|
-
let span = button.appendChild(document.createElement("span"));
|
|
5632
|
-
span.className = "wg-button-label";
|
|
5633
|
-
span.textContent = typeof label == "string" ? label : label(wg.state);
|
|
5634
|
-
}
|
|
5635
|
-
else if ("icon" in label) {
|
|
5636
|
-
let svg = button.appendChild(document.createElementNS(SVG, "svg"));
|
|
5637
|
-
svg.classList.add("wg-icon");
|
|
5638
|
-
svg.setAttribute("viewBox", "0 0 100 100");
|
|
5639
|
-
let path = svg.appendChild(document.createElementNS(SVG, "path"));
|
|
5640
|
-
path.setAttribute("d", label.icon);
|
|
5641
|
-
if (label.directional && !wg.state.textLTR)
|
|
5642
|
-
svg.setAttribute("transform", "scale(-1, 1)");
|
|
5750
|
+
let visible = this.wg.scrollDOM.getBoundingClientRect(), margins = this.wg.getScrollMargins();
|
|
5751
|
+
let visLeft = visible.left + margins.left, visTop = visible.top + margins.top;
|
|
5752
|
+
return {
|
|
5753
|
+
visible: new DOMRect(visLeft, visTop, visible.right - margins.right - visLeft, visible.bottom - margins.bottom - visTop),
|
|
5754
|
+
parent: this.parent ? this.container.getBoundingClientRect() : this.wg.dom.getBoundingClientRect(),
|
|
5755
|
+
pos: this.manager.tooltips.map((t, i) => {
|
|
5756
|
+
let tv = this.manager.tooltipViews[i];
|
|
5757
|
+
return tv.getCoords ? tv.getCoords(t.pos) : this.wg.coordsAtPos(t.pos);
|
|
5758
|
+
}),
|
|
5759
|
+
size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()),
|
|
5760
|
+
space: this.wg.state.facet(tooltipConfig).tooltipSpace(this.wg),
|
|
5761
|
+
scaleX, scaleY, makeAbsolute
|
|
5762
|
+
};
|
|
5643
5763
|
}
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
constructor(item, wg) {
|
|
5651
|
-
this.item = item;
|
|
5652
|
-
this.dom = document.createElement("button");
|
|
5653
|
-
this.dom.className = "wg-menu-button";
|
|
5654
|
-
this.dom.type = "button";
|
|
5655
|
-
this.dom.tabIndex = -1;
|
|
5656
|
-
labelButton(wg, this.dom, item.label);
|
|
5657
|
-
if (item.description) {
|
|
5658
|
-
let desc = typeof item.description == "function" ? item.description(wg.state) : item.description;
|
|
5659
|
-
this.dom.title = desc;
|
|
5660
|
-
this.dom.setAttribute("aria-label", desc);
|
|
5764
|
+
writeMeasure(measured) {
|
|
5765
|
+
if (measured.makeAbsolute) {
|
|
5766
|
+
this.madeAbsolute = true;
|
|
5767
|
+
this.position = "absolute";
|
|
5768
|
+
for (let t of this.manager.tooltipViews)
|
|
5769
|
+
t.dom.style.position = "absolute";
|
|
5661
5770
|
}
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5771
|
+
let { visible, space, scaleX, scaleY } = measured;
|
|
5772
|
+
let others = [];
|
|
5773
|
+
for (let i = 0; i < this.manager.tooltips.length; i++) {
|
|
5774
|
+
let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView;
|
|
5775
|
+
let pos = measured.pos[i], size = measured.size[i];
|
|
5776
|
+
if (!pos || tooltip.clip !== false && (pos.bottom <= Math.max(visible.top, space.top) ||
|
|
5777
|
+
pos.top >= Math.min(visible.bottom, space.bottom) ||
|
|
5778
|
+
pos.right < Math.max(visible.left, space.left) - .1 ||
|
|
5779
|
+
pos.left > Math.min(visible.right, space.right) + .1)) {
|
|
5780
|
+
dom.style.top = Outside;
|
|
5781
|
+
continue;
|
|
5673
5782
|
}
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5783
|
+
let arrow = tooltip.arrow ? tView.dom.querySelector("wg-tooltip-arrow") : null;
|
|
5784
|
+
let arrowHeight = arrow ? 7 : 0;
|
|
5785
|
+
let width = size.right - size.left, height = knownHeight.get(tView) ?? size.bottom - size.top;
|
|
5786
|
+
let offset = tView.offset || noOffset, ltr = this.wg.state.textLTR;
|
|
5787
|
+
let left = size.width > space.right - space.left
|
|
5788
|
+
? (ltr ? space.left : space.right - size.width)
|
|
5789
|
+
: ltr ? Math.max(space.left, Math.min(pos.left - (arrow ? 14 : 0) + offset.x, space.right - width))
|
|
5790
|
+
: Math.min(Math.max(space.left, pos.left - width + (arrow ? 14 : 0) - offset.x), space.right - width);
|
|
5791
|
+
let above = this.above[i];
|
|
5792
|
+
if (!tooltip.strictSide && (above
|
|
5793
|
+
? pos.top - height - arrowHeight - offset.y < space.top
|
|
5794
|
+
: pos.bottom + height + arrowHeight + offset.y > space.bottom) &&
|
|
5795
|
+
above == (space.bottom - pos.bottom > pos.top - space.top))
|
|
5796
|
+
above = this.above[i] = !above;
|
|
5797
|
+
let spaceVert = (above ? pos.top - space.top : space.bottom - pos.bottom) - arrowHeight;
|
|
5798
|
+
if (spaceVert < height && tView.resize !== false) {
|
|
5799
|
+
if (spaceVert < 15) {
|
|
5800
|
+
dom.style.top = Outside;
|
|
5801
|
+
continue;
|
|
5802
|
+
}
|
|
5803
|
+
knownHeight.set(tView, height);
|
|
5804
|
+
dom.style.height = (height = spaceVert) / scaleY + "px";
|
|
5680
5805
|
}
|
|
5681
|
-
if (
|
|
5682
|
-
|
|
5683
|
-
this.dom.setAttribute("aria-pressed", "true");
|
|
5684
|
-
else
|
|
5685
|
-
this.dom.removeAttribute("aria-pressed");
|
|
5806
|
+
else if (dom.style.height) {
|
|
5807
|
+
dom.style.height = "";
|
|
5686
5808
|
}
|
|
5687
|
-
|
|
5809
|
+
let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
|
|
5810
|
+
let right = left + width;
|
|
5811
|
+
if (tView.overlap !== true)
|
|
5812
|
+
for (let r of others)
|
|
5813
|
+
if (r.left < right && r.right > left && r.top < top + height && r.bottom > top)
|
|
5814
|
+
top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2;
|
|
5815
|
+
if (this.position == "absolute") {
|
|
5816
|
+
dom.style.top = (top - measured.parent.top) / scaleY + "px";
|
|
5817
|
+
setLeftStyle(dom, (left - measured.parent.left) / scaleX);
|
|
5818
|
+
}
|
|
5819
|
+
else {
|
|
5820
|
+
dom.style.top = top / scaleY + "px";
|
|
5821
|
+
setLeftStyle(dom, left / scaleX);
|
|
5822
|
+
}
|
|
5823
|
+
if (arrow) {
|
|
5824
|
+
let arrowLeft = pos.left + (ltr ? offset.x : -offset.x) - (left + 14 - 7);
|
|
5825
|
+
arrow.style.left = arrowLeft / scaleX + "px";
|
|
5826
|
+
}
|
|
5827
|
+
if (tView.overlap !== true)
|
|
5828
|
+
others.push({ left, top, right, bottom: top + height });
|
|
5829
|
+
dom.classList.toggle("wg-tooltip-above", above);
|
|
5830
|
+
dom.classList.toggle("wg-tooltip-below", !above);
|
|
5831
|
+
if (tView.positioned)
|
|
5832
|
+
tView.positioned(measured.space);
|
|
5688
5833
|
}
|
|
5689
5834
|
}
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5835
|
+
maybeMeasure() {
|
|
5836
|
+
if (this.manager.tooltips.length)
|
|
5837
|
+
this.wg.scheduleDOMRead(this.measure);
|
|
5693
5838
|
}
|
|
5839
|
+
}, plugin => plugin.eventObserver("scroll", (event, wg, value) => value.maybeMeasure()));
|
|
5840
|
+
function setLeftStyle(elt, value) {
|
|
5841
|
+
let current = parseInt(elt.style.left, 10);
|
|
5842
|
+
if (isNaN(current) || Math.abs(value - current) > 1)
|
|
5843
|
+
elt.style.left = value + "px";
|
|
5694
5844
|
}
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5845
|
+
const styles = /*@__PURE__*/Wordgard.styles({
|
|
5846
|
+
".wg-tooltip": {
|
|
5847
|
+
zIndex: 500,
|
|
5848
|
+
boxSizing: "border-box",
|
|
5849
|
+
backgroundColor: "var(--wg-panel-color)",
|
|
5850
|
+
boxShadow: "0 0 8px 0 rgba(128, 128, 128, 0.2)",
|
|
5851
|
+
font: "var(--wg-dialog-font)",
|
|
5852
|
+
},
|
|
5853
|
+
".wg-tooltip-section:not(:first-child)": {
|
|
5854
|
+
borderTop: "1px solid var(--wg-border-color)",
|
|
5855
|
+
},
|
|
5856
|
+
"wg-tooltip-arrow": {
|
|
5857
|
+
display: "block",
|
|
5858
|
+
height: `${7}px`,
|
|
5859
|
+
width: `${7 * 2}px`,
|
|
5860
|
+
position: "absolute",
|
|
5861
|
+
zIndex: -1,
|
|
5862
|
+
overflow: "hidden",
|
|
5863
|
+
"&:before, &:after": {
|
|
5864
|
+
content: "''",
|
|
5865
|
+
position: "absolute",
|
|
5866
|
+
width: 0,
|
|
5867
|
+
height: 0,
|
|
5868
|
+
borderLeft: `${7}px solid transparent`,
|
|
5869
|
+
borderRight: `${7}px solid transparent`,
|
|
5870
|
+
},
|
|
5871
|
+
".wg-tooltip-above &": {
|
|
5872
|
+
bottom: `-${7}px`,
|
|
5873
|
+
"&:before": {
|
|
5874
|
+
borderTop: `${7}px solid var(--wg-border-color)`,
|
|
5875
|
+
},
|
|
5876
|
+
"&:after": {
|
|
5877
|
+
borderTop: `${7}px solid var(--wg-panel-color)`,
|
|
5878
|
+
bottom: "1px"
|
|
5720
5879
|
}
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
}
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
button;
|
|
5731
|
-
list;
|
|
5732
|
-
flags = 0;
|
|
5733
|
-
activeChild = -3;
|
|
5734
|
-
index = 0;
|
|
5735
|
-
children;
|
|
5736
|
-
constructor(item, children, wg) {
|
|
5737
|
-
this.item = item;
|
|
5738
|
-
this.dom = document.createElement("wg-submenu");
|
|
5739
|
-
this.button = this.dom.appendChild(document.createElement("button"));
|
|
5740
|
-
this.button.type = "button";
|
|
5741
|
-
this.button.tabIndex = -1;
|
|
5742
|
-
this.button.className = "wg-menu-button";
|
|
5743
|
-
this.button.setAttribute("aria-haspopup", "true");
|
|
5744
|
-
this.button.setAttribute("aria-expanded", "false");
|
|
5745
|
-
if (item.description) {
|
|
5746
|
-
let desc = typeof item.description == "function" ? item.description(wg.state) : item.description;
|
|
5747
|
-
this.dom.title = desc;
|
|
5748
|
-
this.dom.setAttribute("aria-label", desc);
|
|
5749
|
-
}
|
|
5750
|
-
if (item.label) {
|
|
5751
|
-
labelButton(wg, this.button, item.label);
|
|
5752
|
-
this.activeChild = -2;
|
|
5753
|
-
}
|
|
5754
|
-
if (item.width != null)
|
|
5755
|
-
this.dom.style.setProperty("--wg-submenu-width", item.width + "ch");
|
|
5756
|
-
if (item.arrow)
|
|
5757
|
-
this.button.classList.add("wg-submenu-arrow");
|
|
5758
|
-
this.list = this.dom.appendChild(document.createElement("wg-menu-list"));
|
|
5759
|
-
this.list.style.display = "none";
|
|
5760
|
-
this.list.role = "menu";
|
|
5761
|
-
this.list.id = id("wg-popup");
|
|
5762
|
-
this.list.setAttribute("aria-label", this.button.title);
|
|
5763
|
-
this.button.setAttribute("aria-controls", this.list.id);
|
|
5764
|
-
this.children = children.filter((ch) => !(ch instanceof BarSpacer));
|
|
5765
|
-
for (let child of children) {
|
|
5766
|
-
this.list.appendChild(child.dom);
|
|
5767
|
-
if (!(child instanceof BarSpacer))
|
|
5768
|
-
child.focusDOM.role = "menuitem";
|
|
5769
|
-
}
|
|
5770
|
-
}
|
|
5771
|
-
get focusDOM() { return this.button; }
|
|
5772
|
-
update(flags, wg) {
|
|
5773
|
-
if (flags != this.flags) {
|
|
5774
|
-
if ((flags & 32) != (this.flags & 32))
|
|
5775
|
-
this.dom.style.display = flags & 32 ? "none" : "";
|
|
5776
|
-
if ((flags & 8) != (this.flags & 8)) {
|
|
5777
|
-
if (flags & 8)
|
|
5778
|
-
this.button.setAttribute("aria-disabled", "true");
|
|
5779
|
-
else
|
|
5780
|
-
this.button.removeAttribute("aria-disabled");
|
|
5781
|
-
}
|
|
5782
|
-
if ((flags & 4) != (this.flags & 4)) {
|
|
5783
|
-
if (flags & 4)
|
|
5784
|
-
this.button.setAttribute("aria-selected", "true");
|
|
5785
|
-
else
|
|
5786
|
-
this.button.removeAttribute("aria-selected");
|
|
5787
|
-
this.button.tabIndex = flags & 4 ? 0 : -1;
|
|
5788
|
-
}
|
|
5789
|
-
if ((flags & 2) != (this.flags & 2))
|
|
5790
|
-
this.list.style.display = flags & 2 ? "" : "none";
|
|
5791
|
-
this.flags = flags;
|
|
5792
|
-
}
|
|
5793
|
-
if (this.activeChild != -2) {
|
|
5794
|
-
let activeChild = this.children.findIndex(ch => ch.flags & 16);
|
|
5795
|
-
if (this.activeChild != activeChild) {
|
|
5796
|
-
this.activeChild = activeChild;
|
|
5797
|
-
let label = activeChild < 0 ? this.item.defaultLabel : this.children[activeChild].item.label;
|
|
5798
|
-
labelButton(wg, this.button, label);
|
|
5880
|
+
},
|
|
5881
|
+
".wg-tooltip-below &": {
|
|
5882
|
+
top: `-${7}px`,
|
|
5883
|
+
"&:before": {
|
|
5884
|
+
borderBottom: `${7}px solid var(--wg-border-color)`,
|
|
5885
|
+
},
|
|
5886
|
+
"&:after": {
|
|
5887
|
+
borderBottom: `${7}px solid var(--wg-panel-color)`,
|
|
5888
|
+
top: "1px"
|
|
5799
5889
|
}
|
|
5800
|
-
}
|
|
5890
|
+
},
|
|
5891
|
+
},
|
|
5892
|
+
});
|
|
5893
|
+
const closeHoverTooltipEffect = /*@__PURE__*/Transaction.Effect.define();
|
|
5894
|
+
const Tooltip = /*@__PURE__*/(function (Tooltip) {
|
|
5895
|
+
function configure(config = {}) {
|
|
5896
|
+
return tooltipConfig.of(config);
|
|
5801
5897
|
}
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5898
|
+
Tooltip.configure = configure;
|
|
5899
|
+
Tooltip.show = GardState.Facet.define({
|
|
5900
|
+
enables: [tooltipPlugin, styles]
|
|
5901
|
+
});
|
|
5902
|
+
function get(wg, tooltip) {
|
|
5903
|
+
let plugin = wg.plugin(tooltipPlugin);
|
|
5904
|
+
if (!plugin)
|
|
5905
|
+
return null;
|
|
5906
|
+
let found = plugin.manager.tooltips.findIndex(typeof tooltip == "function" ? p => p.create == tooltip : p => p == tooltip);
|
|
5907
|
+
return found < 0 ? null : plugin.manager.tooltipViews[found];
|
|
5808
5908
|
}
|
|
5809
|
-
|
|
5810
|
-
function
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5909
|
+
Tooltip.get = get;
|
|
5910
|
+
function reposition(wg) {
|
|
5911
|
+
let plugin = wg.plugin(tooltipPlugin);
|
|
5912
|
+
if (plugin)
|
|
5913
|
+
plugin.maybeMeasure();
|
|
5914
|
+
}
|
|
5915
|
+
Tooltip.reposition = reposition;
|
|
5916
|
+
function hover(source, options = {}) {
|
|
5917
|
+
let setHover = Transaction.Effect.define();
|
|
5918
|
+
let hoverState = GardState.Field.define({
|
|
5919
|
+
create() { return []; },
|
|
5920
|
+
update(value, tr) {
|
|
5921
|
+
if (value.length) {
|
|
5922
|
+
if (options.hideOnChange && (tr.docChanged || tr.selection))
|
|
5923
|
+
value = [];
|
|
5924
|
+
else if (options.hideOn)
|
|
5925
|
+
value = value.filter(v => !options.hideOn(tr, v));
|
|
5926
|
+
if (tr.docChanged) {
|
|
5927
|
+
let mapped = [];
|
|
5928
|
+
for (let tooltip of value) {
|
|
5929
|
+
let newPos = tr.changes.mapPos(tooltip.pos, -1, "around");
|
|
5930
|
+
if (newPos != null) {
|
|
5931
|
+
let copy = Object.assign(Object.create(null), tooltip);
|
|
5932
|
+
copy.pos = newPos;
|
|
5933
|
+
if (copy.end != null)
|
|
5934
|
+
copy.end = tr.changes.mapPos(copy.end);
|
|
5935
|
+
mapped.push(copy);
|
|
5936
|
+
}
|
|
5937
|
+
}
|
|
5938
|
+
value = mapped;
|
|
5939
|
+
}
|
|
5940
|
+
}
|
|
5941
|
+
for (let effect of tr.effects) {
|
|
5942
|
+
if (effect.is(setHover))
|
|
5943
|
+
value = effect.value;
|
|
5944
|
+
if (effect.is(closeHoverTooltipEffect))
|
|
5945
|
+
value = [];
|
|
5946
|
+
}
|
|
5947
|
+
return value;
|
|
5948
|
+
},
|
|
5949
|
+
provide: f => showHoverTooltip.from(f)
|
|
5950
|
+
});
|
|
5951
|
+
return {
|
|
5952
|
+
active: hoverState,
|
|
5953
|
+
extension: [
|
|
5954
|
+
hoverState,
|
|
5955
|
+
Wordgard.Plugin.define(wg => new HoverPlugin(wg, source, hoverState, setHover, options.hoverTime || 300)),
|
|
5956
|
+
showHoverTooltipHost
|
|
5957
|
+
]
|
|
5958
|
+
};
|
|
5959
|
+
}
|
|
5960
|
+
Tooltip.hover = hover;
|
|
5961
|
+
(function (hover) {
|
|
5962
|
+
function has(state) {
|
|
5963
|
+
return state.facet(showHoverTooltip).some(x => x);
|
|
5964
|
+
}
|
|
5965
|
+
hover.has = has;
|
|
5966
|
+
hover.closeAll = closeHoverTooltipEffect.of(null);
|
|
5967
|
+
})(hover = Tooltip.hover || (Tooltip.hover = {}));
|
|
5968
|
+
;return Tooltip})({});
|
|
5969
|
+
const noOffset = { x: 0, y: 0 };
|
|
5970
|
+
const showHoverTooltip = /*@__PURE__*/GardState.Facet.define({
|
|
5971
|
+
combine: inputs => inputs.reduce((a, i) => a.concat(i), [])
|
|
5972
|
+
});
|
|
5973
|
+
class HoverTooltipHost {
|
|
5825
5974
|
wg;
|
|
5975
|
+
manager;
|
|
5826
5976
|
dom;
|
|
5827
|
-
|
|
5828
|
-
|
|
5977
|
+
connected = false;
|
|
5978
|
+
static create(wg) {
|
|
5979
|
+
return new HoverTooltipHost(wg);
|
|
5980
|
+
}
|
|
5829
5981
|
constructor(wg) {
|
|
5830
5982
|
this.wg = wg;
|
|
5831
|
-
this.dom = document.createElement("wg-
|
|
5832
|
-
this.
|
|
5833
|
-
this.dom.addEventListener("keydown", this.key.bind(this));
|
|
5834
|
-
this.dom.addEventListener("mousedown", this.click.bind(this));
|
|
5835
|
-
this.dom.addEventListener("focusout", this.focusout.bind(this));
|
|
5836
|
-
this.items = wg.state.facet(Menu.Item.source);
|
|
5837
|
-
this.init();
|
|
5838
|
-
this.globalClick = this.globalClick.bind(this);
|
|
5983
|
+
this.dom = document.createElement("wg-tooltip-hover");
|
|
5984
|
+
this.manager = new TooltipViewManager(wg, showHoverTooltip, (t, p) => this.createHostedView(t, p), t => t.dom.remove());
|
|
5839
5985
|
}
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
this.
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
this.dom.appendChild(elt.dom);
|
|
5848
|
-
this.selection = this.children.length ? [this.children[0]] : [];
|
|
5849
|
-
this.updateElts(true, this.selection);
|
|
5986
|
+
createHostedView(tooltip, prev) {
|
|
5987
|
+
let hostedView = tooltip.create(this.wg);
|
|
5988
|
+
hostedView.dom.classList.add("wg-tooltip-section");
|
|
5989
|
+
this.dom.insertBefore(hostedView.dom, prev ? prev.dom.nextSibling : this.dom.firstChild);
|
|
5990
|
+
if (this.connected && hostedView.connect)
|
|
5991
|
+
hostedView.connect(this.wg);
|
|
5992
|
+
return hostedView;
|
|
5850
5993
|
}
|
|
5851
|
-
|
|
5852
|
-
let
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5994
|
+
connect(wg) {
|
|
5995
|
+
for (let t of this.manager.tooltipViews)
|
|
5996
|
+
t.connect?.(wg);
|
|
5997
|
+
this.connected = true;
|
|
5998
|
+
}
|
|
5999
|
+
disconnect(wg) {
|
|
6000
|
+
for (let t of this.manager.tooltipViews)
|
|
6001
|
+
t.disconnect?.(wg);
|
|
6002
|
+
this.connected = false;
|
|
6003
|
+
}
|
|
6004
|
+
positioned(space) {
|
|
6005
|
+
for (let hostedView of this.manager.tooltipViews) {
|
|
6006
|
+
if (hostedView.positioned)
|
|
6007
|
+
hostedView.positioned(space);
|
|
5863
6008
|
}
|
|
5864
6009
|
}
|
|
5865
|
-
|
|
5866
|
-
this.
|
|
6010
|
+
update(update) {
|
|
6011
|
+
this.manager.update(update);
|
|
5867
6012
|
}
|
|
5868
|
-
|
|
5869
|
-
let
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
}
|
|
5882
|
-
if (selection.length) {
|
|
5883
|
-
let selected = selection.indexOf(elt);
|
|
5884
|
-
if (selected == selection.length - 1)
|
|
5885
|
-
flags |= 4;
|
|
5886
|
-
else if (selected > -1)
|
|
5887
|
-
flags |= 2;
|
|
6013
|
+
remove(wg) {
|
|
6014
|
+
for (let t of this.manager.tooltipViews)
|
|
6015
|
+
t.remove?.(wg);
|
|
6016
|
+
}
|
|
6017
|
+
passProp(name) {
|
|
6018
|
+
let value = undefined;
|
|
6019
|
+
for (let view of this.manager.tooltipViews) {
|
|
6020
|
+
let given = view[name];
|
|
6021
|
+
if (given !== undefined) {
|
|
6022
|
+
if (value === undefined)
|
|
6023
|
+
value = given;
|
|
6024
|
+
else if (value !== given)
|
|
6025
|
+
return undefined;
|
|
5888
6026
|
}
|
|
5889
|
-
elt.update(flags, this.wg, updateObj);
|
|
5890
|
-
}
|
|
5891
|
-
if (update && selection.some(e => e.flags & 32)) {
|
|
5892
|
-
let reset = selection[0].flags & 32 ? findChild(this.children, true) : selection[0];
|
|
5893
|
-
this.setSelection(reset ? [reset] : [], this.dom.contains(this.wg.root.activeElement));
|
|
5894
6027
|
}
|
|
6028
|
+
return value;
|
|
5895
6029
|
}
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
6030
|
+
get offset() { return this.passProp("offset"); }
|
|
6031
|
+
get getCoords() { return this.passProp("getCoords"); }
|
|
6032
|
+
get overlap() { return this.passProp("overlap"); }
|
|
6033
|
+
get resize() { return this.passProp("resize"); }
|
|
6034
|
+
}
|
|
6035
|
+
const showHoverTooltipHost = /*@__PURE__*/Tooltip.show.derive(state => {
|
|
6036
|
+
let tooltips = state.facet(showHoverTooltip);
|
|
6037
|
+
if (tooltips.length === 0)
|
|
6038
|
+
return null;
|
|
6039
|
+
return {
|
|
6040
|
+
pos: Math.min(...tooltips.map(t => t.pos)),
|
|
6041
|
+
end: Math.max(...tooltips.map(t => t.end ?? t.pos)),
|
|
6042
|
+
create: HoverTooltipHost.create,
|
|
6043
|
+
above: tooltips[0].above,
|
|
6044
|
+
arrow: tooltips.some(t => t.arrow),
|
|
6045
|
+
};
|
|
6046
|
+
});
|
|
6047
|
+
class HoverPlugin {
|
|
6048
|
+
wg;
|
|
6049
|
+
source;
|
|
6050
|
+
field;
|
|
6051
|
+
setHover;
|
|
6052
|
+
hoverTime;
|
|
6053
|
+
lastMove;
|
|
6054
|
+
hoverTimeout = -1;
|
|
6055
|
+
restartTimeout = -1;
|
|
6056
|
+
pending = null;
|
|
6057
|
+
constructor(wg, source, field, setHover, hoverTime) {
|
|
6058
|
+
this.wg = wg;
|
|
6059
|
+
this.source = source;
|
|
6060
|
+
this.field = field;
|
|
6061
|
+
this.setHover = setHover;
|
|
6062
|
+
this.hoverTime = hoverTime;
|
|
6063
|
+
this.lastMove = { x: 0, y: 0, target: wg.dom, time: 0 };
|
|
6064
|
+
this.checkHover = this.checkHover.bind(this);
|
|
6065
|
+
wg.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this));
|
|
6066
|
+
wg.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this));
|
|
5903
6067
|
}
|
|
5904
|
-
|
|
5905
|
-
if (
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
if (sLen) {
|
|
5910
|
-
let forward = (event.key == "ArrowRight") == (getComputedStyle(this.dom).direction == "ltr");
|
|
5911
|
-
let next = findNextChild(this.children, this.selection[0], forward ? 1 : -1);
|
|
5912
|
-
this.setSelection(next ? [next] : []);
|
|
5913
|
-
}
|
|
5914
|
-
}
|
|
5915
|
-
else if (event.key == "ArrowDown" || event.key == "ArrowUp") {
|
|
5916
|
-
if (sLen > 1) {
|
|
5917
|
-
let parent = this.selection[sLen - 2];
|
|
5918
|
-
let next = findNextChild(parent.children, this.selection[sLen - 1], event.key == "ArrowUp" ? -1 : 1);
|
|
5919
|
-
if (next)
|
|
5920
|
-
this.setSelection(this.selection.slice(0, sLen - 1).concat(next));
|
|
5921
|
-
}
|
|
5922
|
-
else if (sLen == 1 && this.selection[0].children) {
|
|
5923
|
-
let inner = defaultChild(this.selection[0].children);
|
|
5924
|
-
if (inner)
|
|
5925
|
-
this.setSelection([this.selection[0], inner]);
|
|
5926
|
-
}
|
|
5927
|
-
}
|
|
5928
|
-
else if (event.key == "Home" || event.key == "End") {
|
|
5929
|
-
let child = findChild(sLen > 1 ? this.selection[sLen - 2].children : this.children, event.key == "Home");
|
|
5930
|
-
if (child)
|
|
5931
|
-
this.setSelection(this.selection.slice(0, sLen - 1).concat(child));
|
|
5932
|
-
}
|
|
5933
|
-
else if (event.key == " " || event.key == "Enter") {
|
|
5934
|
-
if (sLen) {
|
|
5935
|
-
let child = this.selection[sLen - 1];
|
|
5936
|
-
if (child.flags & 8) ;
|
|
5937
|
-
else if (child.children) {
|
|
5938
|
-
let inner = defaultChild(child.children);
|
|
5939
|
-
if (inner)
|
|
5940
|
-
this.setSelection(this.selection.concat(inner));
|
|
5941
|
-
}
|
|
5942
|
-
else {
|
|
5943
|
-
if (child.run)
|
|
5944
|
-
child.run(this.wg);
|
|
5945
|
-
this.setSelection([this.selection[0]]);
|
|
5946
|
-
}
|
|
5947
|
-
}
|
|
5948
|
-
}
|
|
5949
|
-
else if (event.key == "Escape" && sLen > 1) {
|
|
5950
|
-
this.setSelection(this.selection.slice(0, sLen - 1));
|
|
5951
|
-
}
|
|
5952
|
-
else {
|
|
5953
|
-
return;
|
|
6068
|
+
update() {
|
|
6069
|
+
if (this.pending) {
|
|
6070
|
+
this.pending = null;
|
|
6071
|
+
clearTimeout(this.restartTimeout);
|
|
6072
|
+
this.restartTimeout = setTimeout(() => this.startHover(), 20);
|
|
5954
6073
|
}
|
|
5955
|
-
event.preventDefault();
|
|
5956
6074
|
}
|
|
5957
|
-
|
|
5958
|
-
|
|
6075
|
+
get active() {
|
|
6076
|
+
return this.wg.state.field(this.field);
|
|
6077
|
+
}
|
|
6078
|
+
checkHover() {
|
|
6079
|
+
this.hoverTimeout = -1;
|
|
6080
|
+
if (this.active.length)
|
|
5959
6081
|
return;
|
|
5960
|
-
let
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
}
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
if (
|
|
5977
|
-
|
|
5978
|
-
if (next)
|
|
5979
|
-
this.setSelection(this.selection.slice(0, i).concat([target, next]), false);
|
|
5980
|
-
}
|
|
6082
|
+
let hovered = Date.now() - this.lastMove.time;
|
|
6083
|
+
if (hovered < this.hoverTime)
|
|
6084
|
+
this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered);
|
|
6085
|
+
else
|
|
6086
|
+
this.startHover();
|
|
6087
|
+
}
|
|
6088
|
+
startHover() {
|
|
6089
|
+
clearTimeout(this.restartTimeout);
|
|
6090
|
+
let { wg, lastMove } = this;
|
|
6091
|
+
let { pos, side } = wg.posAtCoords(lastMove);
|
|
6092
|
+
let open = this.source(wg, pos, side || -1);
|
|
6093
|
+
if (open?.then) {
|
|
6094
|
+
let pending = this.pending = { pos };
|
|
6095
|
+
open.then(result => {
|
|
6096
|
+
if (this.pending == pending) {
|
|
6097
|
+
this.pending = null;
|
|
6098
|
+
if (result && !(Array.isArray(result) && !result.length))
|
|
6099
|
+
wg.dispatch({ effects: this.setHover.of(Array.isArray(result) ? result : [result]) });
|
|
5981
6100
|
}
|
|
5982
|
-
}
|
|
6101
|
+
}, e => logException(wg.state, e, "hover tooltip"));
|
|
5983
6102
|
}
|
|
5984
|
-
else {
|
|
5985
|
-
|
|
5986
|
-
target.run(this.wg);
|
|
5987
|
-
this.setSelection(this.children.includes(target) ? [target] : this.selection.length ? [this.selection[0]] : [], false);
|
|
6103
|
+
else if (open && !(Array.isArray(open) && !open.length)) {
|
|
6104
|
+
wg.dispatch({ effects: this.setHover.of(Array.isArray(open) ? open : [open]) });
|
|
5988
6105
|
}
|
|
5989
|
-
event.preventDefault();
|
|
5990
6106
|
}
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
6107
|
+
get tooltip() {
|
|
6108
|
+
let plugin = this.wg.plugin(tooltipPlugin);
|
|
6109
|
+
let index = plugin ? plugin.manager.tooltips.findIndex(t => t.create == HoverTooltipHost.create) : -1;
|
|
6110
|
+
return index > -1 ? plugin.manager.tooltipViews[index] : null;
|
|
6111
|
+
}
|
|
6112
|
+
mousemove(event) {
|
|
6113
|
+
this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
|
|
6114
|
+
if (this.hoverTimeout < 0)
|
|
6115
|
+
this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
|
|
6116
|
+
let { active, tooltip } = this;
|
|
6117
|
+
if (active.length && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
|
|
6118
|
+
let { pos } = active[0] || this.pending, end = active[0]?.end ?? pos;
|
|
6119
|
+
if ((pos == end ? this.wg.posAtCoords(this.lastMove).pos != pos
|
|
6120
|
+
: !isOverRange(this.wg, pos, end, event.clientX, event.clientY))) {
|
|
6121
|
+
this.wg.dispatch({ effects: this.setHover.of([]) });
|
|
6122
|
+
this.pending = null;
|
|
6123
|
+
}
|
|
5996
6124
|
}
|
|
5997
6125
|
}
|
|
5998
|
-
|
|
5999
|
-
clearTimeout(this.
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
}, 20);
|
|
6126
|
+
mouseleave(event) {
|
|
6127
|
+
clearTimeout(this.hoverTimeout);
|
|
6128
|
+
this.hoverTimeout = -1;
|
|
6129
|
+
let { active } = this;
|
|
6130
|
+
if (active.length) {
|
|
6131
|
+
let { tooltip } = this;
|
|
6132
|
+
let inTooltip = tooltip && tooltip.dom.contains(event.relatedTarget);
|
|
6133
|
+
if (!inTooltip)
|
|
6134
|
+
this.wg.dispatch({ effects: this.setHover.of([]) });
|
|
6135
|
+
else
|
|
6136
|
+
this.watchTooltipLeave(tooltip.dom);
|
|
6010
6137
|
}
|
|
6011
6138
|
}
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6139
|
+
watchTooltipLeave(tooltip) {
|
|
6140
|
+
let watch = (event) => {
|
|
6141
|
+
tooltip.removeEventListener("mouseleave", watch);
|
|
6142
|
+
if (this.active.length && !this.wg.dom.contains(event.relatedTarget))
|
|
6143
|
+
this.wg.dispatch({ effects: this.setHover.of([]) });
|
|
6144
|
+
};
|
|
6145
|
+
tooltip.addEventListener("mouseleave", watch);
|
|
6015
6146
|
}
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
for (let i = start ? 0 : children.length - 1; start ? i < children.length : i >= 0; start ? i++ : i--) {
|
|
6021
|
-
let child = children[i];
|
|
6022
|
-
if (!(child.flags & 8))
|
|
6023
|
-
return child;
|
|
6147
|
+
remove() {
|
|
6148
|
+
clearTimeout(this.hoverTimeout);
|
|
6149
|
+
this.wg.dom.removeEventListener("mouseleave", this.mouseleave);
|
|
6150
|
+
this.wg.dom.removeEventListener("mousemove", this.mousemove);
|
|
6024
6151
|
}
|
|
6025
|
-
return null;
|
|
6026
6152
|
}
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
else if (i >= children.length)
|
|
6035
|
-
i = 0;
|
|
6036
|
-
if (i == index)
|
|
6037
|
-
return null;
|
|
6038
|
-
let child = children[i];
|
|
6039
|
-
if (!(child.flags & 32))
|
|
6040
|
-
return child;
|
|
6153
|
+
const tooltipMargin = 4;
|
|
6154
|
+
function isInTooltip(tooltip, event) {
|
|
6155
|
+
let { left, right, top, bottom } = tooltip.getBoundingClientRect(), arrow;
|
|
6156
|
+
if (arrow = tooltip.querySelector(".wg-tooltip-arrow")) {
|
|
6157
|
+
let arrowRect = arrow.getBoundingClientRect();
|
|
6158
|
+
top = Math.min(arrowRect.top, top);
|
|
6159
|
+
bottom = Math.max(arrowRect.bottom, bottom);
|
|
6041
6160
|
}
|
|
6161
|
+
return event.clientX >= left - tooltipMargin && event.clientX <= right + tooltipMargin &&
|
|
6162
|
+
event.clientY >= top - tooltipMargin && event.clientY <= bottom + tooltipMargin;
|
|
6042
6163
|
}
|
|
6043
|
-
function
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
},
|
|
6050
|
-
"&light": {
|
|
6051
|
-
"--wg-menu-color": "#555"
|
|
6052
|
-
},
|
|
6053
|
-
"&dark": {
|
|
6054
|
-
"--wg-menu-color": "#ccc"
|
|
6055
|
-
},
|
|
6056
|
-
"wg-menubar": {
|
|
6057
|
-
display: "flex",
|
|
6058
|
-
flexWrap: "wrap",
|
|
6059
|
-
gap: "5px",
|
|
6060
|
-
padding: "3px",
|
|
6061
|
-
color: "var(--wg-menu-color)",
|
|
6062
|
-
borderBottom: "1px solid var(--wg-border-color)",
|
|
6063
|
-
},
|
|
6064
|
-
".wg-menu-button:focus": {
|
|
6065
|
-
outline: "1.5px solid var(--wg-highlight-color)"
|
|
6066
|
-
},
|
|
6067
|
-
".wg-menu-button": {
|
|
6068
|
-
border: 0,
|
|
6069
|
-
padding: "3px",
|
|
6070
|
-
borderRadius: "4px",
|
|
6071
|
-
boxSizing: "content-box",
|
|
6072
|
-
backgroundColor: "transparent",
|
|
6073
|
-
font: "inherit",
|
|
6074
|
-
color: "inherit",
|
|
6075
|
-
height: "var(--wg-menu-item-size)",
|
|
6076
|
-
textAlign: "left",
|
|
6077
|
-
"&[aria-disabled]": {
|
|
6078
|
-
opacity: "0.3"
|
|
6079
|
-
},
|
|
6080
|
-
"&[aria-pressed]": {
|
|
6081
|
-
color: "var(--wg-highlight-color)"
|
|
6082
|
-
},
|
|
6083
|
-
"&:hover": {
|
|
6084
|
-
backgroundColor: "#88888820",
|
|
6085
|
-
},
|
|
6086
|
-
},
|
|
6087
|
-
".wg-button-label": {
|
|
6088
|
-
display: "inline-block",
|
|
6089
|
-
minWidth: "var(--wg-submenu-width)",
|
|
6090
|
-
padding: "0 3px",
|
|
6091
|
-
},
|
|
6092
|
-
"svg.wg-icon": {
|
|
6093
|
-
fill: "currentColor",
|
|
6094
|
-
width: "var(--wg-menu-item-size)",
|
|
6095
|
-
height: "var(--wg-menu-item-size)",
|
|
6096
|
-
},
|
|
6097
|
-
"wg-menu-spacer": {
|
|
6098
|
-
display: "block",
|
|
6099
|
-
width: "7px"
|
|
6100
|
-
},
|
|
6101
|
-
"wg-submenu": {
|
|
6102
|
-
display: "block",
|
|
6103
|
-
position: "relative",
|
|
6104
|
-
lineHeight: ".6",
|
|
6105
|
-
whiteSpace: "nowrap"
|
|
6106
|
-
},
|
|
6107
|
-
"wg-menu-list": {
|
|
6108
|
-
display: "flex",
|
|
6109
|
-
flexDirection: "column",
|
|
6110
|
-
alignItems: "stretch",
|
|
6111
|
-
gap: "5px",
|
|
6112
|
-
padding: "5px",
|
|
6113
|
-
borderRadius: "4px",
|
|
6114
|
-
backgroundColor: "var(--wg-panel-color)",
|
|
6115
|
-
position: "absolute",
|
|
6116
|
-
zIndex: "10",
|
|
6117
|
-
top: "100%",
|
|
6118
|
-
boxShadow: "0 2px 8px 0 rgba(128, 128, 128, 0.2)",
|
|
6119
|
-
"& wg-menu-list": {
|
|
6120
|
-
left: "100%",
|
|
6121
|
-
top: 0
|
|
6122
|
-
}
|
|
6123
|
-
},
|
|
6124
|
-
".wg-submenu-arrow:after": {
|
|
6125
|
-
padding: "0 2px",
|
|
6126
|
-
fontSize: "80%",
|
|
6127
|
-
verticalAlign: "10%",
|
|
6128
|
-
opacity: "0.4",
|
|
6129
|
-
content: "'▾'"
|
|
6130
|
-
},
|
|
6131
|
-
".wg-submenu-arrow.wg-submenu-arrow-open:after": {
|
|
6132
|
-
content: "'▴'"
|
|
6133
|
-
},
|
|
6134
|
-
});
|
|
6135
|
-
const barTemplate = /*@__PURE__*/GardState.Facet.define({
|
|
6136
|
-
combine: inputs => inputs.length ? inputs[0] : [Menu.Group.top.template()]
|
|
6137
|
-
});
|
|
6138
|
-
function menuBar(config = {}) {
|
|
6139
|
-
let extensions = [menuBarPanel, theme];
|
|
6140
|
-
if (config.template)
|
|
6141
|
-
extensions.push(barTemplate.of(Array.isArray(config.template) ? config.template : [config.template]));
|
|
6142
|
-
return extensions;
|
|
6164
|
+
function isOverRange(wg, from, to, x, y, margin) {
|
|
6165
|
+
let rect = wg.contentDOM.getBoundingClientRect();
|
|
6166
|
+
if (rect.left > x || rect.right < x || rect.top > y || rect.bottom < y)
|
|
6167
|
+
return false;
|
|
6168
|
+
let pos = wg.posAtCoords({ x, y }).pos;
|
|
6169
|
+
return pos >= from && pos <= to;
|
|
6143
6170
|
}
|
|
6144
6171
|
|
|
6145
6172
|
const Dialog = /*@__PURE__*/(function (Dialog) {
|
|
6146
6173
|
function show(wg, config) {
|
|
6147
6174
|
let resolve;
|
|
6148
|
-
let
|
|
6149
|
-
let
|
|
6150
|
-
|
|
6151
|
-
|
|
6175
|
+
let result = new Promise(r => resolve = r);
|
|
6176
|
+
let hint = config.positioningHint === true ? PositioningHint.get() : config.positioningHint;
|
|
6177
|
+
let tooltip = hint || !config.tooltip ? null : {
|
|
6178
|
+
...config.tooltip,
|
|
6179
|
+
create: (wg) => createDialog(wg, dialog),
|
|
6180
|
+
}, offset = null;
|
|
6181
|
+
if (hint) {
|
|
6182
|
+
let editorRect = wg.dom.getBoundingClientRect();
|
|
6183
|
+
offset = {
|
|
6184
|
+
x: wg.state.textLTR ? hint.left - editorRect.left : editorRect.right - hint.right,
|
|
6185
|
+
y: hint.bottom - editorRect.top
|
|
6186
|
+
};
|
|
6152
6187
|
}
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6188
|
+
let dialog = new OpenDialog(config, resolve, tooltip, offset);
|
|
6189
|
+
let effects = [openDialog.of(dialog)];
|
|
6190
|
+
if (!wg.state.field(dialogs, false))
|
|
6191
|
+
effects.push(GardState.appendConfig.of([dialogs, renderDialogs]));
|
|
6192
|
+
wg.dispatch({ effects });
|
|
6193
|
+
wg.scheduleDOMRead(() => {
|
|
6194
|
+
if (!wg.state.field(dialogs).includes(dialog))
|
|
6195
|
+
dialog.resolve(null);
|
|
6196
|
+
});
|
|
6197
|
+
return {
|
|
6198
|
+
close: () => doCloseDialog(wg, dialog),
|
|
6199
|
+
result
|
|
6200
|
+
};
|
|
6165
6201
|
}
|
|
6166
6202
|
Dialog.show = show;
|
|
6167
|
-
function get(wg,
|
|
6168
|
-
let
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
}
|
|
6174
|
-
return null;
|
|
6203
|
+
function get(wg, key) {
|
|
6204
|
+
let active = wg.state.field(dialogs, false);
|
|
6205
|
+
let found = active && active.find(d => d.spec.key === key);
|
|
6206
|
+
if (!found)
|
|
6207
|
+
return null;
|
|
6208
|
+
return { dom: dialogDOM(wg, found), close: () => doCloseDialog(wg, found) };
|
|
6175
6209
|
}
|
|
6176
6210
|
Dialog.get = get;
|
|
6177
|
-
function close(wg, className) {
|
|
6178
|
-
let dialogs = wg.state.field(dialogField, false) || [];
|
|
6179
|
-
for (let open of dialogs) {
|
|
6180
|
-
let panel = Panel.get(wg, open);
|
|
6181
|
-
if (panel && panel.dom.classList.contains(className)) {
|
|
6182
|
-
wg.dispatch({ effects: closeDialogEffect.of(open) });
|
|
6183
|
-
return true;
|
|
6184
|
-
}
|
|
6185
|
-
}
|
|
6186
|
-
return false;
|
|
6187
|
-
}
|
|
6188
|
-
Dialog.close = close;
|
|
6189
6211
|
;return Dialog})({});
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
}
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6212
|
+
function dialogDOM(wg, dialog) {
|
|
6213
|
+
let plugin = wg.plugin(renderDialogs);
|
|
6214
|
+
let index = plugin ? plugin.active.indexOf(dialog) : -1;
|
|
6215
|
+
return index > -1 ? plugin.elements[index] : null;
|
|
6216
|
+
}
|
|
6217
|
+
function doCloseDialog(wg, dialog) {
|
|
6218
|
+
let active = wg.state.field(dialogs, false);
|
|
6219
|
+
if (active && active.includes(dialog)) {
|
|
6220
|
+
let dom = dialogDOM(wg, dialog);
|
|
6221
|
+
if (dom && dom.contains(wg.win.document.activeElement))
|
|
6222
|
+
wg.focus();
|
|
6223
|
+
wg.dispatch({ effects: closeDialog.of(dialog) });
|
|
6224
|
+
}
|
|
6225
|
+
}
|
|
6226
|
+
function createDialog(wg, dialog) {
|
|
6227
|
+
let config = dialog.spec;
|
|
6206
6228
|
let content = config.content ? config.content(wg, () => done(null)) : null;
|
|
6207
6229
|
if (!content) {
|
|
6208
6230
|
content = document.createElement("form");
|
|
@@ -6237,10 +6259,7 @@ function createDialog(wg, config, result) {
|
|
|
6237
6259
|
for (let i = 0; i < forms.length; i++) {
|
|
6238
6260
|
let form = forms[i];
|
|
6239
6261
|
form.addEventListener("keydown", (event) => {
|
|
6240
|
-
if (event.keyCode ==
|
|
6241
|
-
done(null);
|
|
6242
|
-
}
|
|
6243
|
-
else if (event.keyCode == 13) { event.preventDefault();
|
|
6262
|
+
if (event.keyCode == 13) { event.preventDefault();
|
|
6244
6263
|
done(form);
|
|
6245
6264
|
}
|
|
6246
6265
|
});
|
|
@@ -6255,691 +6274,1057 @@ function createDialog(wg, config, result) {
|
|
|
6255
6274
|
close.className = "wg-dialog-close";
|
|
6256
6275
|
close.type = "button";
|
|
6257
6276
|
close.append("×");
|
|
6258
|
-
let
|
|
6259
|
-
|
|
6277
|
+
let dom = document.createElement("dialog");
|
|
6278
|
+
dom.open = true;
|
|
6279
|
+
dom.append(content, close);
|
|
6280
|
+
dom.addEventListener("keydown", event => {
|
|
6281
|
+
if (event.keyCode == 27) { event.preventDefault();
|
|
6282
|
+
done(null);
|
|
6283
|
+
}
|
|
6284
|
+
});
|
|
6260
6285
|
if (config.class)
|
|
6261
|
-
|
|
6286
|
+
dom.className = config.class;
|
|
6262
6287
|
function done(form) {
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6288
|
+
dialog.resolve(form);
|
|
6289
|
+
doCloseDialog(wg, dialog);
|
|
6290
|
+
}
|
|
6291
|
+
let focus = null;
|
|
6292
|
+
if (config.focus) {
|
|
6293
|
+
if (typeof config.focus == "string")
|
|
6294
|
+
focus = dom.querySelector(config.focus);
|
|
6295
|
+
else
|
|
6296
|
+
focus = content.querySelector("input") || content.querySelector("button");
|
|
6266
6297
|
}
|
|
6267
|
-
let mustFocus = config.focus;
|
|
6268
6298
|
return {
|
|
6269
|
-
dom
|
|
6270
|
-
top: config.top !== false,
|
|
6299
|
+
dom,
|
|
6271
6300
|
connect: () => {
|
|
6272
|
-
if (
|
|
6273
|
-
|
|
6274
|
-
let focus;
|
|
6275
|
-
if (typeof config.focus == "string")
|
|
6276
|
-
focus = content.querySelector(config.focus);
|
|
6277
|
-
else
|
|
6278
|
-
focus = content.querySelector("input") || content.querySelector("button");
|
|
6279
|
-
if (focus && "select" in focus)
|
|
6301
|
+
if (focus) {
|
|
6302
|
+
if ("select" in focus)
|
|
6280
6303
|
focus.select();
|
|
6281
|
-
else if (
|
|
6304
|
+
else if ("focus" in focus)
|
|
6282
6305
|
focus.focus();
|
|
6306
|
+
focus = null;
|
|
6283
6307
|
}
|
|
6284
6308
|
}
|
|
6285
6309
|
};
|
|
6286
6310
|
}
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
this.facet = facet;
|
|
6298
|
-
this.createTooltipView = createTooltipView;
|
|
6299
|
-
this.removeTooltipView = removeTooltipView;
|
|
6300
|
-
this.input = wg.state.facet(facet);
|
|
6301
|
-
this.tooltips = this.input.filter(t => t);
|
|
6302
|
-
let prev = null;
|
|
6303
|
-
this.tooltipViews = this.tooltips.map(t => prev = createTooltipView(t, prev));
|
|
6311
|
+
class OpenDialog {
|
|
6312
|
+
spec;
|
|
6313
|
+
resolve;
|
|
6314
|
+
tooltip;
|
|
6315
|
+
offset;
|
|
6316
|
+
constructor(spec, resolve, tooltip, offset) {
|
|
6317
|
+
this.spec = spec;
|
|
6318
|
+
this.resolve = resolve;
|
|
6319
|
+
this.tooltip = tooltip;
|
|
6320
|
+
this.offset = offset;
|
|
6304
6321
|
}
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
known = i;
|
|
6322
|
+
}
|
|
6323
|
+
const openDialog = /*@__PURE__*/Transaction.Effect.define();
|
|
6324
|
+
const closeDialog = /*@__PURE__*/Transaction.Effect.define();
|
|
6325
|
+
const dialogs = /*@__PURE__*/GardState.Field.define({
|
|
6326
|
+
create: () => [],
|
|
6327
|
+
update: (value, tr) => {
|
|
6328
|
+
for (let e of tr.effects) {
|
|
6329
|
+
if (e.is(openDialog))
|
|
6330
|
+
value = value.concat(e.value);
|
|
6331
|
+
else if (e.is(closeDialog))
|
|
6332
|
+
value = value.filter(d => d != e.value);
|
|
6333
|
+
}
|
|
6334
|
+
for (let i = 0; i < value.length; i++) {
|
|
6335
|
+
let { closedBy } = value[i].spec;
|
|
6336
|
+
if (closedBy && closedBy(tr)) {
|
|
6337
|
+
value = value.slice(0, i).concat(value.slice(i + 1));
|
|
6338
|
+
i--;
|
|
6323
6339
|
}
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6340
|
+
}
|
|
6341
|
+
return value;
|
|
6342
|
+
},
|
|
6343
|
+
provide: f => Tooltip.show.deriveN(state => {
|
|
6344
|
+
let tooltips = [];
|
|
6345
|
+
for (let d of state.field(f))
|
|
6346
|
+
if (d.tooltip)
|
|
6347
|
+
tooltips.push(d.tooltip);
|
|
6348
|
+
return tooltips;
|
|
6349
|
+
})
|
|
6350
|
+
});
|
|
6351
|
+
const renderDialogs = /*@__PURE__*/Wordgard.Plugin.fromClass(class {
|
|
6352
|
+
active = [];
|
|
6353
|
+
elements = [];
|
|
6354
|
+
mustPosition = false;
|
|
6355
|
+
constructor(wg) {
|
|
6356
|
+
this.positionDialogs = this.positionDialogs.bind(this);
|
|
6357
|
+
this.updateTo(wg, wg.state.field(dialogs));
|
|
6358
|
+
if (this.mustPosition)
|
|
6359
|
+
wg.scheduleDOMRead(this.positionDialogs);
|
|
6360
|
+
}
|
|
6361
|
+
update(update) {
|
|
6362
|
+
let active = update.state.field(dialogs), changed = this.active != active;
|
|
6363
|
+
if (changed)
|
|
6364
|
+
this.updateTo(update.editor, active);
|
|
6365
|
+
if ((update.geometryChanged || changed) && this.mustPosition)
|
|
6366
|
+
update.editor.scheduleDOMRead(this.positionDialogs);
|
|
6367
|
+
}
|
|
6368
|
+
updateTo(wg, active) {
|
|
6369
|
+
for (let i = 0; i < this.active.length; i++)
|
|
6370
|
+
if (!active.includes(this.active[i])) {
|
|
6371
|
+
let elt = this.elements[i], dialog = this.active[i];
|
|
6372
|
+
if (elt)
|
|
6373
|
+
elt.remove();
|
|
6374
|
+
dialog.resolve(null);
|
|
6375
|
+
}
|
|
6376
|
+
this.mustPosition = false;
|
|
6377
|
+
this.elements = active.map((dialog, i) => {
|
|
6378
|
+
if (dialog.tooltip)
|
|
6379
|
+
return null;
|
|
6380
|
+
this.mustPosition = true;
|
|
6381
|
+
let panel;
|
|
6382
|
+
let found = this.active.indexOf(dialog);
|
|
6383
|
+
if (found > -1) {
|
|
6384
|
+
panel = this.elements[found];
|
|
6328
6385
|
}
|
|
6329
6386
|
else {
|
|
6330
|
-
let
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6387
|
+
let { dom, connect } = createDialog(wg, dialog);
|
|
6388
|
+
dom.classList.add("wg-free-dialog");
|
|
6389
|
+
wg.dom.appendChild(dom);
|
|
6390
|
+
connect();
|
|
6391
|
+
panel = dom;
|
|
6392
|
+
}
|
|
6393
|
+
panel.style.zIndex = String(400 + i);
|
|
6394
|
+
return panel;
|
|
6395
|
+
});
|
|
6396
|
+
this.active = active;
|
|
6397
|
+
}
|
|
6398
|
+
positionDialogs(wg) {
|
|
6399
|
+
let sizes = this.elements.map(e => e && e.getBoundingClientRect());
|
|
6400
|
+
let editor = wg.dom.getBoundingClientRect();
|
|
6401
|
+
let windowWidth = wg.win.innerWidth, windowHeight = wg.win.innerHeight;
|
|
6402
|
+
let midX = (Math.max(0, editor.left) + Math.min(windowWidth, editor.right)) / 2;
|
|
6403
|
+
let midY = (Math.max(0, editor.top) + Math.min(windowHeight, editor.bottom)) / 2;
|
|
6404
|
+
let ltr = wg.state.textLTR;
|
|
6405
|
+
wg.scheduleDOMWrite(() => {
|
|
6406
|
+
for (let i = 0; i < sizes.length; i++) {
|
|
6407
|
+
let size = sizes[i];
|
|
6408
|
+
if (!size)
|
|
6409
|
+
continue;
|
|
6410
|
+
let { offset } = this.active[i];
|
|
6411
|
+
let baseX, baseY;
|
|
6412
|
+
if (offset) {
|
|
6413
|
+
baseY = editor.top + offset.y;
|
|
6414
|
+
baseX = ltr ? editor.left + offset.x : editor.right - offset.x - size.width;
|
|
6415
|
+
}
|
|
6416
|
+
else {
|
|
6417
|
+
baseX = midX - size.width / 2;
|
|
6418
|
+
baseY = midY - size.height / 2;
|
|
6419
|
+
}
|
|
6420
|
+
if (baseX < 0)
|
|
6421
|
+
baseX = 0;
|
|
6422
|
+
else if (baseX + size.width > windowWidth && size.width < windowWidth)
|
|
6423
|
+
baseX = windowWidth - size.width;
|
|
6424
|
+
if (baseY < 0)
|
|
6425
|
+
baseY = 0;
|
|
6426
|
+
else if (baseY + size.height > windowHeight && size.height < windowHeight)
|
|
6427
|
+
baseY = windowHeight - size.height;
|
|
6428
|
+
let elt = this.elements[i];
|
|
6429
|
+
elt.style.left = baseX + "px";
|
|
6430
|
+
elt.style.top = baseY + "px";
|
|
6335
6431
|
}
|
|
6432
|
+
});
|
|
6433
|
+
}
|
|
6434
|
+
destroy() {
|
|
6435
|
+
for (let elt of this.elements)
|
|
6436
|
+
if (elt)
|
|
6437
|
+
elt.remove();
|
|
6438
|
+
for (let dialog of this.active)
|
|
6439
|
+
dialog.resolve(null);
|
|
6440
|
+
}
|
|
6441
|
+
}, plugin => plugin.eventHandler("scroll", (event, wg, val) => {
|
|
6442
|
+
if (val.mustPosition)
|
|
6443
|
+
wg.scheduleDOMRead(val.positionDialogs);
|
|
6444
|
+
}));
|
|
6445
|
+
const PositioningHint = /*@__PURE__*/(function (PositioningHint) {
|
|
6446
|
+
let currentHint = null;
|
|
6447
|
+
function runWith(hint, run) {
|
|
6448
|
+
let prev = currentHint;
|
|
6449
|
+
currentHint = hint;
|
|
6450
|
+
try {
|
|
6451
|
+
return run();
|
|
6336
6452
|
}
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
this.removeTooltipView(t);
|
|
6340
|
-
if (update.editor.connected)
|
|
6341
|
-
t.disconnect?.(update.editor);
|
|
6342
|
-
t.remove?.(update.editor);
|
|
6343
|
-
}
|
|
6344
|
-
if (above) {
|
|
6345
|
-
newAbove.forEach((val, i) => above[i] = val);
|
|
6346
|
-
above.length = newAbove.length;
|
|
6453
|
+
finally {
|
|
6454
|
+
currentHint = prev;
|
|
6347
6455
|
}
|
|
6348
|
-
this.input = input;
|
|
6349
|
-
this.tooltips = tooltips;
|
|
6350
|
-
this.tooltipViews = tooltipViews;
|
|
6351
|
-
return true;
|
|
6352
6456
|
}
|
|
6457
|
+
PositioningHint.runWith = runWith;
|
|
6458
|
+
function get() {
|
|
6459
|
+
return currentHint ? currentHint() : null;
|
|
6460
|
+
}
|
|
6461
|
+
PositioningHint.get = get;
|
|
6462
|
+
;return PositioningHint})({});
|
|
6463
|
+
|
|
6464
|
+
function collectKeyDescs(bindings) {
|
|
6465
|
+
let groups = [];
|
|
6466
|
+
let add = (group, key, desc) => {
|
|
6467
|
+
let found = groups.find(g => g.group == group);
|
|
6468
|
+
if (!found)
|
|
6469
|
+
groups.push(found = { group, bindings: [] });
|
|
6470
|
+
found.bindings.push({ key, desc });
|
|
6471
|
+
};
|
|
6472
|
+
for (let binding of bindings) {
|
|
6473
|
+
let group = binding.spec.group || null;
|
|
6474
|
+
let name = binding.spec[currentPlatform] || binding.spec.key;
|
|
6475
|
+
if (name) {
|
|
6476
|
+
if (binding.spec.description)
|
|
6477
|
+
add(group, normalizeKeyName(name, currentPlatform), binding.spec.description);
|
|
6478
|
+
if (binding.spec.shiftDescription)
|
|
6479
|
+
add(group, "Shift-" + normalizeKeyName(name, currentPlatform), binding.spec.shiftDescription);
|
|
6480
|
+
}
|
|
6481
|
+
}
|
|
6482
|
+
return groups.sort((a, b) => (a.group?.rank ?? 0) - (b.group?.rank || 0));
|
|
6483
|
+
}
|
|
6484
|
+
function resolveText(state, text) {
|
|
6485
|
+
return typeof text == "string" ? text : text(state);
|
|
6486
|
+
}
|
|
6487
|
+
function renderKeyDescs(state, groups) {
|
|
6488
|
+
let frag = document.createDocumentFragment();
|
|
6489
|
+
frag.append(cr("h3", { class: "wg-dialog-title" }, phrases.get(state, "key_bindings")));
|
|
6490
|
+
frag.append(cr("div", { class: "wg-key-list", tabindex: "-1" }, groups.map(group => [
|
|
6491
|
+
group.group ? cr("h4", resolveText(state, group.group.description)) : null,
|
|
6492
|
+
group.bindings.map(({ key, desc }) => [
|
|
6493
|
+
cr("div", cr("kbd", key)),
|
|
6494
|
+
cr("div", resolveText(state, desc))
|
|
6495
|
+
])
|
|
6496
|
+
])));
|
|
6497
|
+
return frag;
|
|
6498
|
+
}
|
|
6499
|
+
function keyBindingHelp() {
|
|
6500
|
+
return [keyBindingHelp.keyBindings, keyBindingHelp.button];
|
|
6501
|
+
}
|
|
6502
|
+
;keyBindingHelp = /*@__PURE__*/(function (keyBindingHelp) {
|
|
6503
|
+
keyBindingHelp.showKeyBindings = wg => {
|
|
6504
|
+
let open = Dialog.get(wg, keyBindingHelp.showKeyBindings);
|
|
6505
|
+
if (open) {
|
|
6506
|
+
open.close();
|
|
6507
|
+
return true;
|
|
6508
|
+
}
|
|
6509
|
+
let descs = collectKeyDescs(wg.state.field(KeyBinding.keymap));
|
|
6510
|
+
if (!descs.length)
|
|
6511
|
+
return false;
|
|
6512
|
+
Dialog.show(wg, {
|
|
6513
|
+
key: keyBindingHelp.showKeyBindings,
|
|
6514
|
+
content: () => renderKeyDescs(wg.state, descs),
|
|
6515
|
+
class: "wg-key-help",
|
|
6516
|
+
focus: ".wg-key-list",
|
|
6517
|
+
positioningHint: true
|
|
6518
|
+
});
|
|
6519
|
+
return true;
|
|
6520
|
+
};
|
|
6521
|
+
keyBindingHelp.button = Menu.Button.define({
|
|
6522
|
+
run: keyBindingHelp.showKeyBindings,
|
|
6523
|
+
label: { icon: "M24 31c-2 0-4-2-4-4C22 14 32 5 49 5c17 0 28 10 28 24 0 10-5 17-13 22-8 5-11 8-11 15v0a4 4 0 0 1-4 4h-6a4 4 0 0 1-4-4l0-1c0-9 4-15 12-20 8-5 10-9 10-15 0-7-6-13-14-13-8 0-13 4-15 11 0 2-2 3-4 3h-6ZM46 95c5 0 8-4 8-8 0-5-4-8-8-8-5 0-8 4-8 8S42 95 46 95" },
|
|
6524
|
+
description: phrases.ref("show_keys"),
|
|
6525
|
+
parent: Menu.Group.top,
|
|
6526
|
+
rank: 99
|
|
6527
|
+
});
|
|
6528
|
+
keyBindingHelp.keyBindings = [
|
|
6529
|
+
KeyBinding.of({ key: "Mod-?", run: keyBindingHelp.showKeyBindings, description: phrases.ref("show_keys"),
|
|
6530
|
+
shift: keyBindingHelp.showKeyBindings }),
|
|
6531
|
+
KeyBinding.of({ key: "Mod-Shift-/", run: keyBindingHelp.showKeyBindings }),
|
|
6532
|
+
];
|
|
6533
|
+
;return keyBindingHelp})(keyBindingHelp);
|
|
6534
|
+
|
|
6535
|
+
function offset(add, offset) {
|
|
6536
|
+
return (v, from, to) => add(v, from + offset, to == null ? undefined : to + offset);
|
|
6353
6537
|
}
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
})
|
|
6360
|
-
});
|
|
6361
|
-
const knownHeight = /*@__PURE__*/(() => new WeakMap())();
|
|
6362
|
-
const tooltipPlugin = /*@__PURE__*/Wordgard.Plugin.fromClass(class {
|
|
6363
|
-
wg;
|
|
6364
|
-
manager;
|
|
6365
|
-
above = [];
|
|
6366
|
-
inView = true;
|
|
6367
|
-
position;
|
|
6368
|
-
madeAbsolute = false;
|
|
6369
|
-
parent;
|
|
6370
|
-
classes;
|
|
6371
|
-
intersectionObserver;
|
|
6372
|
-
resizeObserver;
|
|
6373
|
-
lastTransaction = 0;
|
|
6374
|
-
measureTimeout = -1;
|
|
6375
|
-
constructor(wg) {
|
|
6376
|
-
this.wg = wg;
|
|
6377
|
-
let config = wg.state.facet(tooltipConfig);
|
|
6378
|
-
this.position = config.position;
|
|
6379
|
-
this.parent = config.parent;
|
|
6380
|
-
this.classes = wg.themeClasses;
|
|
6381
|
-
this.createContainer();
|
|
6382
|
-
this.measure = this.measure.bind(this);
|
|
6383
|
-
this.resizeObserver = typeof ResizeObserver == "function" ? new ResizeObserver(() => this.measureSoon()) : null;
|
|
6384
|
-
this.manager = new TooltipViewManager(wg, Tooltip.show, (t, p) => this.createTooltip(t, p), t => {
|
|
6385
|
-
if (this.resizeObserver)
|
|
6386
|
-
this.resizeObserver.unobserve(t.dom);
|
|
6387
|
-
t.dom.remove();
|
|
6538
|
+
function init(type, create, source, doc) {
|
|
6539
|
+
return create(add => {
|
|
6540
|
+
doc.iterate((node, pos) => {
|
|
6541
|
+
if (node.isPlot && doc.schema.matchNode(node.type, type))
|
|
6542
|
+
source(node, pos + 1, add);
|
|
6388
6543
|
});
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6544
|
+
});
|
|
6545
|
+
}
|
|
6546
|
+
function refreshByPred(type, source, doc, deco, pred) {
|
|
6547
|
+
let recreate = [];
|
|
6548
|
+
doc.iterate((node, pos) => {
|
|
6549
|
+
if (doc.schema.matchNode(node.type, type) && pred(node))
|
|
6550
|
+
recreate.push({
|
|
6551
|
+
from: pos, to: pos + node.length,
|
|
6552
|
+
add: add => source(node, pos + 1, add)
|
|
6553
|
+
});
|
|
6554
|
+
});
|
|
6555
|
+
return recreate.length ? deco.modify({ replace: recreate }) : deco;
|
|
6556
|
+
}
|
|
6557
|
+
function update(config, create, source, deco, tr) {
|
|
6558
|
+
let doc = tr.newDoc;
|
|
6559
|
+
let refresh = config.refresh && config.refresh(tr);
|
|
6560
|
+
if (refresh === true)
|
|
6561
|
+
return init(config.type, create, source, doc);
|
|
6562
|
+
if (refresh)
|
|
6563
|
+
deco = refreshByPred(config.type, source, tr.startState.doc, deco, refresh);
|
|
6564
|
+
if (!tr.docChanged && !refresh)
|
|
6565
|
+
return deco;
|
|
6566
|
+
let recreate = [];
|
|
6567
|
+
let clear = [];
|
|
6568
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
6569
|
+
let covered = false;
|
|
6570
|
+
doc.iterate(fromB, toB, (node, pos) => {
|
|
6571
|
+
if (doc.schema.matchNode(node.type, config.type) && !recreate.some(r => r.from == pos)) {
|
|
6572
|
+
recreate.push({
|
|
6573
|
+
from: pos, to: pos + node.length,
|
|
6574
|
+
add: add => source(node, pos + 1, add)
|
|
6575
|
+
});
|
|
6576
|
+
if (pos < toB && pos + node.length > toB)
|
|
6577
|
+
covered = true;
|
|
6578
|
+
return false;
|
|
6579
|
+
}
|
|
6580
|
+
});
|
|
6581
|
+
if (!covered) {
|
|
6582
|
+
let end = tr.startState.doc.resolve(toA);
|
|
6583
|
+
let open = end.matchingParent(p => doc.schema.matchNode(p.type, config.type));
|
|
6584
|
+
if (open && open.before >= fromA)
|
|
6585
|
+
clear.push({ from: open.before, to: open.after });
|
|
6407
6586
|
}
|
|
6587
|
+
});
|
|
6588
|
+
if (clear.length)
|
|
6589
|
+
deco = deco.modify({ replace: clear });
|
|
6590
|
+
deco = deco.map(tr.changes, recreate);
|
|
6591
|
+
return deco;
|
|
6592
|
+
}
|
|
6593
|
+
function decoratePlots(config) {
|
|
6594
|
+
let result = [];
|
|
6595
|
+
let { type, points, ranges } = config;
|
|
6596
|
+
if (points) {
|
|
6597
|
+
let source = (plot, start, add) => points(plot, offset(add, start));
|
|
6598
|
+
let field = GardState.Field.define({
|
|
6599
|
+
create(state) { return init(type, PointSet.create, source, state.doc); },
|
|
6600
|
+
update(value, tr) { return update(config, PointSet.create, source, value, tr); }
|
|
6601
|
+
});
|
|
6602
|
+
result.push(field, Decoration.Point.source.of(s => s.field(field)));
|
|
6408
6603
|
}
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6604
|
+
if (ranges) {
|
|
6605
|
+
let source = (plot, start, add) => ranges(plot, offset(add, start));
|
|
6606
|
+
let field = GardState.Field.define({
|
|
6607
|
+
create(state) { return init(type, RangeSet.create, source, state.doc); },
|
|
6608
|
+
update(value, tr) { return update(config, RangeSet.create, source, value, tr); }
|
|
6609
|
+
});
|
|
6610
|
+
result.push(field, Decoration.Range.source.of(s => s.field(field)));
|
|
6611
|
+
}
|
|
6612
|
+
return result;
|
|
6613
|
+
}
|
|
6614
|
+
|
|
6615
|
+
const panelConfig = /*@__PURE__*/GardState.Facet.define({
|
|
6616
|
+
combine(configs) {
|
|
6617
|
+
let topContainer, bottomContainer;
|
|
6618
|
+
for (let c of configs) {
|
|
6619
|
+
topContainer ||= c.topContainer;
|
|
6620
|
+
bottomContainer ||= c.bottomContainer;
|
|
6414
6621
|
}
|
|
6622
|
+
return { topContainer, bottomContainer };
|
|
6415
6623
|
}
|
|
6416
|
-
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
6624
|
+
});
|
|
6625
|
+
const panelPlugin = /*@__PURE__*/Wordgard.Plugin.fromClass(class {
|
|
6626
|
+
input;
|
|
6627
|
+
specs;
|
|
6628
|
+
panels;
|
|
6629
|
+
top;
|
|
6630
|
+
bottom;
|
|
6631
|
+
constructor(wg) {
|
|
6632
|
+
this.input = wg.state.facet(Panel.show);
|
|
6633
|
+
this.specs = this.input.filter(s => s);
|
|
6634
|
+
this.panels = this.specs.map(spec => spec(wg));
|
|
6635
|
+
for (let p of this.panels)
|
|
6636
|
+
p.dom.classList.add("wg-panel");
|
|
6637
|
+
let conf = wg.state.facet(panelConfig);
|
|
6638
|
+
this.top = new PanelGroup(wg, true, conf.topContainer);
|
|
6639
|
+
this.bottom = new PanelGroup(wg, false, conf.bottomContainer);
|
|
6640
|
+
this.top.sync(this.panels.filter(p => p.top), wg);
|
|
6641
|
+
this.bottom.sync(this.panels.filter(p => !p.top), wg);
|
|
6422
6642
|
}
|
|
6423
6643
|
update(update) {
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
this.observeIntersection();
|
|
6429
|
-
let shouldMeasure = updated || update.geometryChanged;
|
|
6430
|
-
let newConfig = update.state.facet(tooltipConfig);
|
|
6431
|
-
if (newConfig.position != this.position && !this.madeAbsolute) {
|
|
6432
|
-
this.position = newConfig.position;
|
|
6433
|
-
for (let t of this.manager.tooltipViews)
|
|
6434
|
-
t.dom.style.position = this.position;
|
|
6435
|
-
shouldMeasure = true;
|
|
6644
|
+
let conf = update.state.facet(panelConfig);
|
|
6645
|
+
if (this.top.container != conf.topContainer) {
|
|
6646
|
+
this.top.sync([], update.editor);
|
|
6647
|
+
this.top = new PanelGroup(update.editor, true, conf.topContainer);
|
|
6436
6648
|
}
|
|
6437
|
-
if (
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
this.parent = newConfig.parent;
|
|
6441
|
-
this.createContainer();
|
|
6442
|
-
for (let t of this.manager.tooltipViews)
|
|
6443
|
-
this.container.appendChild(t.dom);
|
|
6444
|
-
shouldMeasure = true;
|
|
6649
|
+
if (this.bottom.container != conf.bottomContainer) {
|
|
6650
|
+
this.bottom.sync([], update.editor);
|
|
6651
|
+
this.bottom = new PanelGroup(update.editor, false, conf.bottomContainer);
|
|
6445
6652
|
}
|
|
6446
|
-
|
|
6447
|
-
|
|
6653
|
+
this.top.syncClasses();
|
|
6654
|
+
this.bottom.syncClasses();
|
|
6655
|
+
let input = update.state.facet(Panel.show);
|
|
6656
|
+
if (input != this.input) {
|
|
6657
|
+
let specs = input.filter(x => x);
|
|
6658
|
+
let panels = [], top = [], bottom = [], mount = [];
|
|
6659
|
+
for (let spec of specs) {
|
|
6660
|
+
let known = this.specs.indexOf(spec), panel;
|
|
6661
|
+
if (known < 0) {
|
|
6662
|
+
panel = spec(update.editor);
|
|
6663
|
+
mount.push(panel);
|
|
6664
|
+
}
|
|
6665
|
+
else {
|
|
6666
|
+
panel = this.panels[known];
|
|
6667
|
+
if (panel.update)
|
|
6668
|
+
panel.update(update);
|
|
6669
|
+
}
|
|
6670
|
+
panels.push(panel);
|
|
6671
|
+
(panel.top ? top : bottom).push(panel);
|
|
6672
|
+
}
|
|
6673
|
+
this.specs = specs;
|
|
6674
|
+
this.panels = panels;
|
|
6675
|
+
this.top.sync(top, update.editor);
|
|
6676
|
+
this.bottom.sync(bottom, update.editor);
|
|
6677
|
+
for (let p of mount) {
|
|
6678
|
+
p.dom.classList.add("wg-panel");
|
|
6679
|
+
if (p.connect && update.editor.connected)
|
|
6680
|
+
p.connect(update.editor);
|
|
6681
|
+
}
|
|
6448
6682
|
}
|
|
6449
|
-
|
|
6450
|
-
this.
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
let tooltipView = tooltip.create(this.wg);
|
|
6454
|
-
let before = prev ? prev.dom : null;
|
|
6455
|
-
tooltipView.dom.classList.add("wg-tooltip");
|
|
6456
|
-
if (tooltip.arrow && !tooltipView.dom.querySelector(".wg-tooltip > wg-tooltip-arrow")) {
|
|
6457
|
-
let arrow = document.createElement("wg-tooltip-arrow");
|
|
6458
|
-
tooltipView.dom.appendChild(arrow);
|
|
6683
|
+
else {
|
|
6684
|
+
for (let p of this.panels)
|
|
6685
|
+
if (p.update)
|
|
6686
|
+
p.update(update);
|
|
6459
6687
|
}
|
|
6460
|
-
tooltipView.dom.style.position = this.position;
|
|
6461
|
-
tooltipView.dom.style.top = Outside;
|
|
6462
|
-
tooltipView.dom.style.left = "0px";
|
|
6463
|
-
this.container.insertBefore(tooltipView.dom, before);
|
|
6464
|
-
if (this.wg.connected)
|
|
6465
|
-
tooltipView.connect?.(this.wg);
|
|
6466
|
-
if (this.resizeObserver && this.wg.connected)
|
|
6467
|
-
this.resizeObserver.observe(tooltipView.dom);
|
|
6468
|
-
return tooltipView;
|
|
6469
6688
|
}
|
|
6470
6689
|
connect(wg) {
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
t.connect?.(wg);
|
|
6474
|
-
if (this.resizeObserver)
|
|
6475
|
-
this.resizeObserver.observe(t.dom);
|
|
6476
|
-
}
|
|
6477
|
-
this.observeIntersection();
|
|
6690
|
+
for (let p of this.panels)
|
|
6691
|
+
p.connect?.(wg);
|
|
6478
6692
|
}
|
|
6479
6693
|
disconnect(wg) {
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
t.disconnect?.(wg);
|
|
6483
|
-
if (this.resizeObserver)
|
|
6484
|
-
this.resizeObserver.unobserve(t.dom);
|
|
6485
|
-
}
|
|
6486
|
-
if (this.intersectionObserver)
|
|
6487
|
-
this.intersectionObserver.disconnect();
|
|
6694
|
+
for (let p of this.panels)
|
|
6695
|
+
p.disconnect?.(wg);
|
|
6488
6696
|
}
|
|
6489
|
-
remove() {
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
if (this.wg.connected)
|
|
6493
|
-
tooltipView.disconnect?.(this.wg);
|
|
6494
|
-
tooltipView.remove?.(this.wg);
|
|
6495
|
-
}
|
|
6496
|
-
if (this.parent)
|
|
6497
|
-
this.container.remove();
|
|
6498
|
-
clearTimeout(this.measureTimeout);
|
|
6697
|
+
remove(wg) {
|
|
6698
|
+
this.top.sync([], wg);
|
|
6699
|
+
this.bottom.sync([], wg);
|
|
6499
6700
|
}
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6701
|
+
}, plugin => Wordgard.coveredMargins.of(wg => {
|
|
6702
|
+
let value = wg.plugin(plugin);
|
|
6703
|
+
return value && { top: value.top.scrollMargin(), bottom: value.bottom.scrollMargin() };
|
|
6704
|
+
}));
|
|
6705
|
+
const Panel = /*@__PURE__*/(function (Panel) {
|
|
6706
|
+
Panel.show = GardState.Facet.define({
|
|
6707
|
+
enables: panelPlugin
|
|
6708
|
+
});
|
|
6709
|
+
function get(wg, constructor) {
|
|
6710
|
+
let plugin = wg.plugin(panelPlugin);
|
|
6711
|
+
let index = plugin ? plugin.specs.indexOf(constructor) : -1;
|
|
6712
|
+
return index > -1 ? plugin.panels[index] : null;
|
|
6503
6713
|
}
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6714
|
+
Panel.get = get;
|
|
6715
|
+
function configure(config) {
|
|
6716
|
+
return config ? [panelConfig.of(config)] : [];
|
|
6717
|
+
}
|
|
6718
|
+
Panel.configure = configure;
|
|
6719
|
+
;return Panel})({});
|
|
6720
|
+
class PanelGroup {
|
|
6721
|
+
wg;
|
|
6722
|
+
top;
|
|
6723
|
+
container;
|
|
6724
|
+
dom = undefined;
|
|
6725
|
+
classes = "";
|
|
6726
|
+
panels = [];
|
|
6727
|
+
constructor(wg, top, container) {
|
|
6728
|
+
this.wg = wg;
|
|
6729
|
+
this.top = top;
|
|
6730
|
+
this.container = container;
|
|
6731
|
+
this.syncClasses();
|
|
6732
|
+
}
|
|
6733
|
+
sync(panels, wg) {
|
|
6734
|
+
for (let p of this.panels)
|
|
6735
|
+
if (!panels.includes(p)) {
|
|
6736
|
+
if (wg.connected)
|
|
6737
|
+
p.disconnect?.(wg);
|
|
6738
|
+
p.remove?.(wg);
|
|
6514
6739
|
}
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6740
|
+
this.panels = panels;
|
|
6741
|
+
this.syncDOM();
|
|
6742
|
+
}
|
|
6743
|
+
syncDOM() {
|
|
6744
|
+
if (this.panels.length == 0) {
|
|
6745
|
+
if (this.dom) {
|
|
6746
|
+
this.dom.remove();
|
|
6747
|
+
this.dom = undefined;
|
|
6521
6748
|
}
|
|
6749
|
+
return;
|
|
6522
6750
|
}
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
parent
|
|
6528
|
-
pos: this.manager.tooltips.map((t, i) => {
|
|
6529
|
-
let tv = this.manager.tooltipViews[i];
|
|
6530
|
-
return tv.getCoords ? tv.getCoords(t.pos) : this.wg.coordsAtPos(t.pos);
|
|
6531
|
-
}),
|
|
6532
|
-
size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()),
|
|
6533
|
-
space: this.wg.state.facet(tooltipConfig).tooltipSpace(this.wg),
|
|
6534
|
-
scaleX, scaleY, makeAbsolute
|
|
6535
|
-
};
|
|
6536
|
-
}
|
|
6537
|
-
writeMeasure(measured) {
|
|
6538
|
-
if (measured.makeAbsolute) {
|
|
6539
|
-
this.madeAbsolute = true;
|
|
6540
|
-
this.position = "absolute";
|
|
6541
|
-
for (let t of this.manager.tooltipViews)
|
|
6542
|
-
t.dom.style.position = "absolute";
|
|
6751
|
+
if (!this.dom) {
|
|
6752
|
+
this.dom = document.createElement("wg-panels");
|
|
6753
|
+
this.dom.className = this.top ? "wg-panels-top" : "wg-panels-bottom";
|
|
6754
|
+
let parent = this.container || this.wg.dom;
|
|
6755
|
+
parent.insertBefore(this.dom, this.top ? parent.firstChild : null);
|
|
6543
6756
|
}
|
|
6544
|
-
let
|
|
6545
|
-
let
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
pos.top >= Math.min(visible.bottom, space.bottom) ||
|
|
6551
|
-
pos.right < Math.max(visible.left, space.left) - .1 ||
|
|
6552
|
-
pos.left > Math.min(visible.right, space.right) + .1)) {
|
|
6553
|
-
dom.style.top = Outside;
|
|
6554
|
-
continue;
|
|
6555
|
-
}
|
|
6556
|
-
let arrow = tooltip.arrow ? tView.dom.querySelector("wg-tooltip-arrow") : null;
|
|
6557
|
-
let arrowHeight = arrow ? 7 : 0;
|
|
6558
|
-
let width = size.right - size.left, height = knownHeight.get(tView) ?? size.bottom - size.top;
|
|
6559
|
-
let offset = tView.offset || noOffset, ltr = this.wg.state.textLTR;
|
|
6560
|
-
let left = size.width > space.right - space.left
|
|
6561
|
-
? (ltr ? space.left : space.right - size.width)
|
|
6562
|
-
: ltr ? Math.max(space.left, Math.min(pos.left - (arrow ? 14 : 0) + offset.x, space.right - width))
|
|
6563
|
-
: Math.min(Math.max(space.left, pos.left - width + (arrow ? 14 : 0) - offset.x), space.right - width);
|
|
6564
|
-
let above = this.above[i];
|
|
6565
|
-
if (!tooltip.strictSide && (above
|
|
6566
|
-
? pos.top - height - arrowHeight - offset.y < space.top
|
|
6567
|
-
: pos.bottom + height + arrowHeight + offset.y > space.bottom) &&
|
|
6568
|
-
above == (space.bottom - pos.bottom > pos.top - space.top))
|
|
6569
|
-
above = this.above[i] = !above;
|
|
6570
|
-
let spaceVert = (above ? pos.top - space.top : space.bottom - pos.bottom) - arrowHeight;
|
|
6571
|
-
if (spaceVert < height && tView.resize !== false) {
|
|
6572
|
-
if (spaceVert < 15) {
|
|
6573
|
-
dom.style.top = Outside;
|
|
6574
|
-
continue;
|
|
6575
|
-
}
|
|
6576
|
-
knownHeight.set(tView, height);
|
|
6577
|
-
dom.style.height = (height = spaceVert) / scaleY + "px";
|
|
6578
|
-
}
|
|
6579
|
-
else if (dom.style.height) {
|
|
6580
|
-
dom.style.height = "";
|
|
6581
|
-
}
|
|
6582
|
-
let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
|
|
6583
|
-
let right = left + width;
|
|
6584
|
-
if (tView.overlap !== true)
|
|
6585
|
-
for (let r of others)
|
|
6586
|
-
if (r.left < right && r.right > left && r.top < top + height && r.bottom > top)
|
|
6587
|
-
top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2;
|
|
6588
|
-
if (this.position == "absolute") {
|
|
6589
|
-
dom.style.top = (top - measured.parent.top) / scaleY + "px";
|
|
6590
|
-
setLeftStyle(dom, (left - measured.parent.left) / scaleX);
|
|
6757
|
+
let curDOM = this.dom.firstChild;
|
|
6758
|
+
for (let panel of this.panels) {
|
|
6759
|
+
if (panel.dom.parentNode == this.dom) {
|
|
6760
|
+
while (curDOM != panel.dom)
|
|
6761
|
+
curDOM = rmDOM(curDOM);
|
|
6762
|
+
curDOM = curDOM.nextSibling;
|
|
6591
6763
|
}
|
|
6592
6764
|
else {
|
|
6593
|
-
dom.
|
|
6594
|
-
setLeftStyle(dom, left / scaleX);
|
|
6595
|
-
}
|
|
6596
|
-
if (arrow) {
|
|
6597
|
-
let arrowLeft = pos.left + (ltr ? offset.x : -offset.x) - (left + 14 - 7);
|
|
6598
|
-
arrow.style.left = arrowLeft / scaleX + "px";
|
|
6765
|
+
this.dom.insertBefore(panel.dom, curDOM);
|
|
6599
6766
|
}
|
|
6600
|
-
if (tView.overlap !== true)
|
|
6601
|
-
others.push({ left, top, right, bottom: top + height });
|
|
6602
|
-
dom.classList.toggle("wg-tooltip-above", above);
|
|
6603
|
-
dom.classList.toggle("wg-tooltip-below", !above);
|
|
6604
|
-
if (tView.positioned)
|
|
6605
|
-
tView.positioned(measured.space);
|
|
6606
6767
|
}
|
|
6768
|
+
while (curDOM)
|
|
6769
|
+
curDOM = rmDOM(curDOM);
|
|
6607
6770
|
}
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6771
|
+
scrollMargin() {
|
|
6772
|
+
return !this.dom || this.container ? 0
|
|
6773
|
+
: Math.max(0, this.top ?
|
|
6774
|
+
this.dom.getBoundingClientRect().bottom - Math.max(0, this.wg.scrollDOM.getBoundingClientRect().top) :
|
|
6775
|
+
Math.min(innerHeight, this.wg.scrollDOM.getBoundingClientRect().bottom) - this.dom.getBoundingClientRect().top);
|
|
6776
|
+
}
|
|
6777
|
+
syncClasses() {
|
|
6778
|
+
if (!this.container || this.classes == this.wg.themeClasses)
|
|
6779
|
+
return;
|
|
6780
|
+
for (let cls of this.classes.split(" "))
|
|
6781
|
+
if (cls)
|
|
6782
|
+
this.container.classList.remove(cls);
|
|
6783
|
+
for (let cls of (this.classes = this.wg.themeClasses).split(" "))
|
|
6784
|
+
if (cls)
|
|
6785
|
+
this.container.classList.add(cls);
|
|
6611
6786
|
}
|
|
6612
|
-
}, plugin => plugin.eventObserver("scroll", (event, wg, value) => value.maybeMeasure()));
|
|
6613
|
-
function setLeftStyle(elt, value) {
|
|
6614
|
-
let current = parseInt(elt.style.left, 10);
|
|
6615
|
-
if (isNaN(current) || Math.abs(value - current) > 1)
|
|
6616
|
-
elt.style.left = value + "px";
|
|
6617
6787
|
}
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6788
|
+
|
|
6789
|
+
let nextID = 0;
|
|
6790
|
+
function id(prefix) {
|
|
6791
|
+
return prefix + "-" + (nextID++ % 0xffffff).toString(16);
|
|
6792
|
+
}
|
|
6793
|
+
const SVG = "http://www.w3.org/2000/svg";
|
|
6794
|
+
function labelButton(wg, button, label) {
|
|
6795
|
+
button.textContent = "";
|
|
6796
|
+
if (!label) ;
|
|
6797
|
+
else if (typeof label == "function" || typeof label == "string") {
|
|
6798
|
+
let span = button.appendChild(document.createElement("span"));
|
|
6799
|
+
span.className = "wg-button-label";
|
|
6800
|
+
span.textContent = typeof label == "string" ? label : label(wg.state);
|
|
6801
|
+
}
|
|
6802
|
+
else if ("icon" in label) {
|
|
6803
|
+
let svg = button.appendChild(document.createElementNS(SVG, "svg"));
|
|
6804
|
+
svg.classList.add("wg-icon");
|
|
6805
|
+
svg.setAttribute("viewBox", "0 0 100 100");
|
|
6806
|
+
let path = svg.appendChild(document.createElementNS(SVG, "path"));
|
|
6807
|
+
path.setAttribute("d", label.icon);
|
|
6808
|
+
if (label.directional && !wg.state.textLTR)
|
|
6809
|
+
svg.setAttribute("transform", "scale(-1, 1)");
|
|
6810
|
+
}
|
|
6811
|
+
}
|
|
6812
|
+
class BarButton {
|
|
6813
|
+
item;
|
|
6814
|
+
dom;
|
|
6815
|
+
flags = 0;
|
|
6816
|
+
index = 0;
|
|
6817
|
+
constructor(item, wg) {
|
|
6818
|
+
this.item = item;
|
|
6819
|
+
this.dom = document.createElement("button");
|
|
6820
|
+
this.dom.className = "wg-menu-button";
|
|
6821
|
+
this.dom.type = "button";
|
|
6822
|
+
this.dom.tabIndex = -1;
|
|
6823
|
+
labelButton(wg, this.dom, item.label);
|
|
6824
|
+
this.setDesc(wg);
|
|
6825
|
+
}
|
|
6826
|
+
setDesc(wg) {
|
|
6827
|
+
let { item: { label, description } } = this;
|
|
6828
|
+
let someDesc = description || (typeof label == "string" || typeof label == "function" ? label : null);
|
|
6829
|
+
let key = someDesc ? KeyBinding.lookupByDescription(wg.state, someDesc) : null;
|
|
6830
|
+
let desc = typeof someDesc == "function" ? someDesc(wg.state) : someDesc;
|
|
6831
|
+
if (description)
|
|
6832
|
+
this.dom.setAttribute("aria-label", desc);
|
|
6833
|
+
else
|
|
6834
|
+
this.dom.removeAttribute("aria-label");
|
|
6835
|
+
if (key)
|
|
6836
|
+
this.dom.setAttribute("aria-keyshortcuts", key);
|
|
6837
|
+
else
|
|
6838
|
+
this.dom.removeAttribute("aria-keyshortcuts");
|
|
6839
|
+
this.dom.title = desc ? desc + (key ? ` (${key})` : "") : key || "";
|
|
6840
|
+
}
|
|
6841
|
+
get focusDOM() { return this.dom; }
|
|
6842
|
+
update(flags, wg, update) {
|
|
6843
|
+
if (flags != this.flags) {
|
|
6844
|
+
if ((flags & 32) != (this.flags & 32))
|
|
6845
|
+
this.dom.style.display = flags & 32 ? "none" : "";
|
|
6846
|
+
if ((flags & 8) != (this.flags & 8)) {
|
|
6847
|
+
if (flags & 8)
|
|
6848
|
+
this.dom.setAttribute("aria-disabled", "true");
|
|
6849
|
+
else
|
|
6850
|
+
this.dom.removeAttribute("aria-disabled");
|
|
6652
6851
|
}
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
"&:after": {
|
|
6660
|
-
borderBottom: `${7}px solid var(--wg-panel-color)`,
|
|
6661
|
-
top: "1px"
|
|
6852
|
+
if ((flags & 4) != (this.flags & 4)) {
|
|
6853
|
+
if (flags & 4)
|
|
6854
|
+
this.dom.setAttribute("aria-selected", "true");
|
|
6855
|
+
else
|
|
6856
|
+
this.dom.removeAttribute("aria-selected");
|
|
6857
|
+
this.dom.tabIndex = flags & 4 ? 0 : -1;
|
|
6662
6858
|
}
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6859
|
+
if ((flags & 16) != (this.flags & 16)) {
|
|
6860
|
+
if (flags & 16)
|
|
6861
|
+
this.dom.setAttribute("aria-pressed", "true");
|
|
6862
|
+
else
|
|
6863
|
+
this.dom.removeAttribute("aria-pressed");
|
|
6864
|
+
}
|
|
6865
|
+
this.flags = flags;
|
|
6866
|
+
}
|
|
6670
6867
|
}
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
let plugin = wg.plugin(tooltipPlugin);
|
|
6677
|
-
if (!plugin)
|
|
6678
|
-
return null;
|
|
6679
|
-
let found = plugin.manager.tooltips.findIndex(typeof tooltip == "function" ? p => p.create == tooltip : p => p == tooltip);
|
|
6680
|
-
return found < 0 ? null : plugin.manager.tooltipViews[found];
|
|
6868
|
+
get children() { return null; }
|
|
6869
|
+
run(wg) {
|
|
6870
|
+
PositioningHint.runWith(() => this.dom.getBoundingClientRect(), () => {
|
|
6871
|
+
Command.dispatch(wg, this.item.run);
|
|
6872
|
+
});
|
|
6681
6873
|
}
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6874
|
+
}
|
|
6875
|
+
class BarControl {
|
|
6876
|
+
item;
|
|
6877
|
+
dom;
|
|
6878
|
+
focusDOM;
|
|
6879
|
+
flags = 0;
|
|
6880
|
+
index = 0;
|
|
6881
|
+
constructor(item, wg, done) {
|
|
6882
|
+
this.item = item;
|
|
6883
|
+
let { dom, focus } = item.render(wg, done);
|
|
6884
|
+
this.dom = dom;
|
|
6885
|
+
this.focusDOM = focus || dom;
|
|
6886
|
+
this.focusDOM.tabIndex = -1;
|
|
6687
6887
|
}
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
if (newPos != null) {
|
|
6704
|
-
let copy = Object.assign(Object.create(null), tooltip);
|
|
6705
|
-
copy.pos = newPos;
|
|
6706
|
-
if (copy.end != null)
|
|
6707
|
-
copy.end = tr.changes.mapPos(copy.end);
|
|
6708
|
-
mapped.push(copy);
|
|
6709
|
-
}
|
|
6710
|
-
}
|
|
6711
|
-
value = mapped;
|
|
6712
|
-
}
|
|
6713
|
-
}
|
|
6714
|
-
for (let effect of tr.effects) {
|
|
6715
|
-
if (effect.is(setHover))
|
|
6716
|
-
value = effect.value;
|
|
6717
|
-
if (effect.is(closeHoverTooltipEffect))
|
|
6718
|
-
value = [];
|
|
6719
|
-
}
|
|
6720
|
-
return value;
|
|
6721
|
-
},
|
|
6722
|
-
provide: f => showHoverTooltip.from(f)
|
|
6723
|
-
});
|
|
6724
|
-
return {
|
|
6725
|
-
active: hoverState,
|
|
6726
|
-
extension: [
|
|
6727
|
-
hoverState,
|
|
6728
|
-
Wordgard.Plugin.define(wg => new HoverPlugin(wg, source, hoverState, setHover, options.hoverTime || 300)),
|
|
6729
|
-
showHoverTooltipHost
|
|
6730
|
-
]
|
|
6731
|
-
};
|
|
6888
|
+
update(flags, wg, update) {
|
|
6889
|
+
if (flags != this.flags) {
|
|
6890
|
+
if ((flags & 32) != (this.flags & 32))
|
|
6891
|
+
this.dom.style.display = flags & 32 ? "none" : "";
|
|
6892
|
+
if ((flags & 8) != (this.flags & 8) && this.item.setEnabled)
|
|
6893
|
+
this.item.setEnabled(this.dom, !(flags & 8));
|
|
6894
|
+
if ((flags & 4) != (this.flags & 4)) {
|
|
6895
|
+
if (flags & 4)
|
|
6896
|
+
this.focusDOM.setAttribute("aria-selected", "true");
|
|
6897
|
+
else
|
|
6898
|
+
this.focusDOM.removeAttribute("aria-selected");
|
|
6899
|
+
this.focusDOM.tabIndex = flags & 4 ? 0 : -1;
|
|
6900
|
+
}
|
|
6901
|
+
this.flags = flags;
|
|
6902
|
+
}
|
|
6732
6903
|
}
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6904
|
+
get children() { return null; }
|
|
6905
|
+
get run() { return null; }
|
|
6906
|
+
}
|
|
6907
|
+
class BarSubmenu {
|
|
6908
|
+
item;
|
|
6909
|
+
dom;
|
|
6910
|
+
button;
|
|
6911
|
+
list;
|
|
6912
|
+
flags = 0;
|
|
6913
|
+
activeChild = -3;
|
|
6914
|
+
index = 0;
|
|
6915
|
+
children;
|
|
6916
|
+
constructor(item, children, wg) {
|
|
6917
|
+
this.item = item;
|
|
6918
|
+
this.dom = document.createElement("wg-submenu");
|
|
6919
|
+
this.button = this.dom.appendChild(document.createElement("button"));
|
|
6920
|
+
this.button.type = "button";
|
|
6921
|
+
this.button.tabIndex = -1;
|
|
6922
|
+
this.button.className = "wg-menu-button";
|
|
6923
|
+
this.button.setAttribute("aria-haspopup", "true");
|
|
6924
|
+
this.button.setAttribute("aria-expanded", "false");
|
|
6925
|
+
if (item.description) {
|
|
6926
|
+
let desc = typeof item.description == "function" ? item.description(wg.state) : item.description;
|
|
6927
|
+
this.dom.title = desc;
|
|
6928
|
+
this.dom.setAttribute("aria-label", desc);
|
|
6929
|
+
}
|
|
6930
|
+
if (item.label) {
|
|
6931
|
+
labelButton(wg, this.button, item.label);
|
|
6932
|
+
this.activeChild = -2;
|
|
6933
|
+
}
|
|
6934
|
+
if (item.width != null)
|
|
6935
|
+
this.dom.style.setProperty("--wg-submenu-width", item.width + "ch");
|
|
6936
|
+
if (item.arrow)
|
|
6937
|
+
this.button.classList.add("wg-submenu-arrow");
|
|
6938
|
+
this.list = this.dom.appendChild(document.createElement("wg-menu-list"));
|
|
6939
|
+
this.list.style.display = "none";
|
|
6940
|
+
this.list.role = "menu";
|
|
6941
|
+
this.list.id = id("wg-popup");
|
|
6942
|
+
this.list.setAttribute("aria-label", this.button.title);
|
|
6943
|
+
this.button.setAttribute("aria-controls", this.list.id);
|
|
6944
|
+
this.children = children.filter((ch) => !(ch instanceof BarSpacer));
|
|
6945
|
+
for (let child of children) {
|
|
6946
|
+
this.list.appendChild(child.dom);
|
|
6947
|
+
if (!(child instanceof BarSpacer))
|
|
6948
|
+
child.focusDOM.role = "menuitem";
|
|
6949
|
+
}
|
|
6950
|
+
}
|
|
6951
|
+
get focusDOM() { return this.button; }
|
|
6952
|
+
update(flags, wg) {
|
|
6953
|
+
if (flags != this.flags) {
|
|
6954
|
+
if ((flags & 32) != (this.flags & 32))
|
|
6955
|
+
this.dom.style.display = flags & 32 ? "none" : "";
|
|
6956
|
+
if ((flags & 8) != (this.flags & 8)) {
|
|
6957
|
+
if (flags & 8)
|
|
6958
|
+
this.button.setAttribute("aria-disabled", "true");
|
|
6959
|
+
else
|
|
6960
|
+
this.button.removeAttribute("aria-disabled");
|
|
6961
|
+
}
|
|
6962
|
+
if ((flags & 4) != (this.flags & 4)) {
|
|
6963
|
+
if (flags & 4)
|
|
6964
|
+
this.button.setAttribute("aria-selected", "true");
|
|
6965
|
+
else
|
|
6966
|
+
this.button.removeAttribute("aria-selected");
|
|
6967
|
+
this.button.tabIndex = flags & 4 ? 0 : -1;
|
|
6968
|
+
}
|
|
6969
|
+
if ((flags & 2) != (this.flags & 2))
|
|
6970
|
+
this.list.style.display = flags & 2 ? "" : "none";
|
|
6971
|
+
this.flags = flags;
|
|
6737
6972
|
}
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
}
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6973
|
+
if (this.activeChild != -2) {
|
|
6974
|
+
let activeChild = this.children.findIndex(ch => ch.flags & 16);
|
|
6975
|
+
if (this.activeChild != activeChild) {
|
|
6976
|
+
this.activeChild = activeChild;
|
|
6977
|
+
let label = activeChild < 0 ? this.item.defaultLabel : this.children[activeChild].item.label;
|
|
6978
|
+
labelButton(wg, this.button, label);
|
|
6979
|
+
}
|
|
6980
|
+
}
|
|
6981
|
+
}
|
|
6982
|
+
get run() { return null; }
|
|
6983
|
+
}
|
|
6984
|
+
class BarSpacer {
|
|
6749
6985
|
dom;
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
return new HoverTooltipHost(wg);
|
|
6986
|
+
constructor() {
|
|
6987
|
+
this.dom = document.createElement("wg-menu-spacer");
|
|
6753
6988
|
}
|
|
6989
|
+
}
|
|
6990
|
+
function instantiate(item, bar, flat) {
|
|
6991
|
+
let elt;
|
|
6992
|
+
if (item instanceof Menu.Submenu.Resolved)
|
|
6993
|
+
elt = new BarSubmenu(item.item, item.content.map(i => instantiate(i, bar, flat)), bar.wg);
|
|
6994
|
+
else if (item === "|")
|
|
6995
|
+
return new BarSpacer();
|
|
6996
|
+
else if (item instanceof Menu.Button)
|
|
6997
|
+
elt = new BarButton(item, bar.wg);
|
|
6998
|
+
else
|
|
6999
|
+
elt = new BarControl(item, bar.wg, () => bar.up());
|
|
7000
|
+
elt.index = flat.length;
|
|
7001
|
+
flat.push(elt);
|
|
7002
|
+
return elt;
|
|
7003
|
+
}
|
|
7004
|
+
class MenuBar {
|
|
7005
|
+
wg;
|
|
7006
|
+
dom;
|
|
7007
|
+
focusTimeout = -1;
|
|
7008
|
+
items;
|
|
6754
7009
|
constructor(wg) {
|
|
6755
7010
|
this.wg = wg;
|
|
6756
|
-
this.dom = document.createElement("wg-
|
|
6757
|
-
this.
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
this.
|
|
6763
|
-
|
|
6764
|
-
hostedView.connect(this.wg);
|
|
6765
|
-
return hostedView;
|
|
6766
|
-
}
|
|
6767
|
-
connect(wg) {
|
|
6768
|
-
for (let t of this.manager.tooltipViews)
|
|
6769
|
-
t.connect?.(wg);
|
|
6770
|
-
this.connected = true;
|
|
6771
|
-
}
|
|
6772
|
-
disconnect(wg) {
|
|
6773
|
-
for (let t of this.manager.tooltipViews)
|
|
6774
|
-
t.disconnect?.(wg);
|
|
6775
|
-
this.connected = false;
|
|
7011
|
+
this.dom = document.createElement("wg-menubar");
|
|
7012
|
+
this.dom.role = "toolbar";
|
|
7013
|
+
this.dom.addEventListener("keydown", this.key.bind(this));
|
|
7014
|
+
this.dom.addEventListener("mousedown", this.click.bind(this));
|
|
7015
|
+
this.dom.addEventListener("focusout", this.focusout.bind(this));
|
|
7016
|
+
this.items = wg.state.facet(Menu.Item.source);
|
|
7017
|
+
this.init();
|
|
7018
|
+
this.globalClick = this.globalClick.bind(this);
|
|
6776
7019
|
}
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
7020
|
+
static create(wg) { return new MenuBar(wg); }
|
|
7021
|
+
init() {
|
|
7022
|
+
let elts = [];
|
|
7023
|
+
this.elts = elts;
|
|
7024
|
+
let children = Menu.resolve(this.items, this.wg.state.facet(barTemplate)).map(i => instantiate(i, this, elts));
|
|
7025
|
+
this.children = children.filter((ch) => !(ch instanceof BarSpacer));
|
|
7026
|
+
for (let elt of children)
|
|
7027
|
+
this.dom.appendChild(elt.dom);
|
|
7028
|
+
this.selection = this.children.length ? [this.children[0]] : [];
|
|
7029
|
+
this.updateElts(true, this.selection);
|
|
6782
7030
|
}
|
|
6783
7031
|
update(update) {
|
|
6784
|
-
|
|
7032
|
+
let items = update.state.facet(Menu.Item.source);
|
|
7033
|
+
if (items != this.items ||
|
|
7034
|
+
update.startState.facet(barTemplate) != update.state.facet(barTemplate) ||
|
|
7035
|
+
update.startState.textLTR != update.state.textLTR ||
|
|
7036
|
+
PhraseSet.didChange(update.startState, update.state)) {
|
|
7037
|
+
this.items = items;
|
|
7038
|
+
this.dom.textContent = "";
|
|
7039
|
+
this.init();
|
|
7040
|
+
}
|
|
7041
|
+
else {
|
|
7042
|
+
this.updateElts(update, this.selection);
|
|
7043
|
+
if (update.startState.facet(KeyBinding.source) != update.state.facet(KeyBinding.source)) {
|
|
7044
|
+
for (let elt of this.elts)
|
|
7045
|
+
if (elt instanceof BarButton)
|
|
7046
|
+
elt.setDesc(update.editor);
|
|
7047
|
+
}
|
|
7048
|
+
}
|
|
6785
7049
|
}
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
t.remove?.(wg);
|
|
7050
|
+
connect() {
|
|
7051
|
+
this.dom.setAttribute("aria-controls", this.wg.contentDOM.id);
|
|
6789
7052
|
}
|
|
6790
|
-
|
|
6791
|
-
let
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
7053
|
+
updateElts(update, selection) {
|
|
7054
|
+
let { state } = this.wg;
|
|
7055
|
+
let changed = typeof update == "boolean" ? update : update.docChanged || update.selectionSet;
|
|
7056
|
+
let updateObj = typeof update == "boolean" ? null : update;
|
|
7057
|
+
for (let i = 0; i < this.elts.length; i++) {
|
|
7058
|
+
let elt = this.elts[i], flags;
|
|
7059
|
+
if (update && (update === true || (elt.item.updateFor ? update.transactions.some(tr => elt.item.updateFor(tr)) : changed))) {
|
|
7060
|
+
flags = ((elt.item.select ? elt.item.select(state) : true) ? 0 : 32) |
|
|
7061
|
+
((elt.item.enable ? elt.item.enable(state) : true) ? 0 : 8) |
|
|
7062
|
+
((elt.item instanceof Menu.Button && elt.item.active ? elt.item.active(state) : false) ? 16 : 0);
|
|
6799
7063
|
}
|
|
7064
|
+
else {
|
|
7065
|
+
flags = elt.flags & (32 | 8 | 16);
|
|
7066
|
+
}
|
|
7067
|
+
if (selection.length) {
|
|
7068
|
+
let selected = selection.indexOf(elt);
|
|
7069
|
+
if (selected == selection.length - 1)
|
|
7070
|
+
flags |= 4;
|
|
7071
|
+
else if (selected > -1)
|
|
7072
|
+
flags |= 2;
|
|
7073
|
+
}
|
|
7074
|
+
elt.update(flags, this.wg, updateObj);
|
|
7075
|
+
}
|
|
7076
|
+
if (update && selection.some(e => e.flags & 32)) {
|
|
7077
|
+
let reset = selection[0].flags & 32 ? findChild(this.children, true) : selection[0];
|
|
7078
|
+
this.setSelection(reset ? [reset] : [], this.dom.contains(this.wg.root.activeElement));
|
|
6800
7079
|
}
|
|
6801
|
-
return value;
|
|
6802
7080
|
}
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
if (tooltips.length === 0)
|
|
6811
|
-
return null;
|
|
6812
|
-
return {
|
|
6813
|
-
pos: Math.min(...tooltips.map(t => t.pos)),
|
|
6814
|
-
end: Math.max(...tooltips.map(t => t.end ?? t.pos)),
|
|
6815
|
-
create: HoverTooltipHost.create,
|
|
6816
|
-
above: tooltips[0].above,
|
|
6817
|
-
arrow: tooltips.some(t => t.arrow),
|
|
6818
|
-
};
|
|
6819
|
-
});
|
|
6820
|
-
class HoverPlugin {
|
|
6821
|
-
wg;
|
|
6822
|
-
source;
|
|
6823
|
-
field;
|
|
6824
|
-
setHover;
|
|
6825
|
-
hoverTime;
|
|
6826
|
-
lastMove;
|
|
6827
|
-
hoverTimeout = -1;
|
|
6828
|
-
restartTimeout = -1;
|
|
6829
|
-
pending = null;
|
|
6830
|
-
constructor(wg, source, field, setHover, hoverTime) {
|
|
6831
|
-
this.wg = wg;
|
|
6832
|
-
this.source = source;
|
|
6833
|
-
this.field = field;
|
|
6834
|
-
this.setHover = setHover;
|
|
6835
|
-
this.hoverTime = hoverTime;
|
|
6836
|
-
this.lastMove = { x: 0, y: 0, target: wg.dom, time: 0 };
|
|
6837
|
-
this.checkHover = this.checkHover.bind(this);
|
|
6838
|
-
wg.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this));
|
|
6839
|
-
wg.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this));
|
|
7081
|
+
setSelection(selection, focus = true) {
|
|
7082
|
+
this.updateElts(false, selection);
|
|
7083
|
+
if (selection.length > 1 && this.selection.length <= 1)
|
|
7084
|
+
this.dom.ownerDocument.addEventListener("mousedown", this.globalClick);
|
|
7085
|
+
this.selection = selection;
|
|
7086
|
+
if (focus && selection.length)
|
|
7087
|
+
selection[selection.length - 1].focusDOM.focus();
|
|
6840
7088
|
}
|
|
6841
|
-
|
|
6842
|
-
if (
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
7089
|
+
key(event) {
|
|
7090
|
+
if (event.ctrlKey || event.altKey || event.metaKey || event.defaultPrevented)
|
|
7091
|
+
return;
|
|
7092
|
+
let sLen = this.selection.length;
|
|
7093
|
+
if (event.key == "ArrowLeft" || event.key == "ArrowRight") {
|
|
7094
|
+
if (sLen) {
|
|
7095
|
+
let forward = (event.key == "ArrowRight") == (getComputedStyle(this.dom).direction == "ltr");
|
|
7096
|
+
let next = findNextChild(this.children, this.selection[0], forward ? 1 : -1);
|
|
7097
|
+
this.setSelection(next ? [next] : []);
|
|
7098
|
+
}
|
|
7099
|
+
}
|
|
7100
|
+
else if (event.key == "ArrowDown" || event.key == "ArrowUp") {
|
|
7101
|
+
if (sLen > 1) {
|
|
7102
|
+
let parent = this.selection[sLen - 2];
|
|
7103
|
+
let next = findNextChild(parent.children, this.selection[sLen - 1], event.key == "ArrowUp" ? -1 : 1);
|
|
7104
|
+
if (next)
|
|
7105
|
+
this.setSelection(this.selection.slice(0, sLen - 1).concat(next));
|
|
7106
|
+
}
|
|
7107
|
+
else if (sLen == 1 && this.selection[0].children) {
|
|
7108
|
+
let inner = defaultChild(this.selection[0].children);
|
|
7109
|
+
if (inner)
|
|
7110
|
+
this.setSelection([this.selection[0], inner]);
|
|
7111
|
+
}
|
|
7112
|
+
}
|
|
7113
|
+
else if (event.key == "Home" || event.key == "End") {
|
|
7114
|
+
let child = findChild(sLen > 1 ? this.selection[sLen - 2].children : this.children, event.key == "Home");
|
|
7115
|
+
if (child)
|
|
7116
|
+
this.setSelection(this.selection.slice(0, sLen - 1).concat(child));
|
|
7117
|
+
}
|
|
7118
|
+
else if (event.key == " " || event.key == "Enter") {
|
|
7119
|
+
if (sLen) {
|
|
7120
|
+
let child = this.selection[sLen - 1];
|
|
7121
|
+
if (child.flags & 8) ;
|
|
7122
|
+
else if (child.children) {
|
|
7123
|
+
let inner = defaultChild(child.children);
|
|
7124
|
+
if (inner)
|
|
7125
|
+
this.setSelection(this.selection.concat(inner));
|
|
7126
|
+
}
|
|
7127
|
+
else {
|
|
7128
|
+
if (child.run)
|
|
7129
|
+
child.run(this.wg);
|
|
7130
|
+
this.setSelection([this.selection[0]]);
|
|
7131
|
+
}
|
|
7132
|
+
}
|
|
7133
|
+
}
|
|
7134
|
+
else if (event.key == "Escape" && sLen > 1) {
|
|
7135
|
+
this.setSelection(this.selection.slice(0, sLen - 1));
|
|
7136
|
+
}
|
|
7137
|
+
else {
|
|
7138
|
+
return;
|
|
6846
7139
|
}
|
|
7140
|
+
event.preventDefault();
|
|
6847
7141
|
}
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
}
|
|
6851
|
-
checkHover() {
|
|
6852
|
-
this.hoverTimeout = -1;
|
|
6853
|
-
if (this.active.length)
|
|
7142
|
+
click(event) {
|
|
7143
|
+
if (event.defaultPrevented)
|
|
6854
7144
|
return;
|
|
6855
|
-
let
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
this.
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
this.
|
|
6871
|
-
if (
|
|
6872
|
-
|
|
7145
|
+
let target, idx;
|
|
7146
|
+
for (let node = event.target;; node = node.parentNode) {
|
|
7147
|
+
if (!node || node == this.dom)
|
|
7148
|
+
return;
|
|
7149
|
+
target = this.elts.find(e => e.dom == node);
|
|
7150
|
+
if (target)
|
|
7151
|
+
break;
|
|
7152
|
+
}
|
|
7153
|
+
if (target.flags & 8) ;
|
|
7154
|
+
else if (target.children) {
|
|
7155
|
+
if ((idx = this.selection.indexOf(target)) > -1 && idx < this.selection.length - 1) {
|
|
7156
|
+
this.setSelection(this.selection.slice(0, idx + 1), false);
|
|
7157
|
+
}
|
|
7158
|
+
else {
|
|
7159
|
+
for (let i = 0; i < this.selection.length; i++) {
|
|
7160
|
+
let { children } = i ? this.selection[i - 1] : this;
|
|
7161
|
+
if (children.includes(target)) {
|
|
7162
|
+
let next = defaultChild(target.children);
|
|
7163
|
+
if (next)
|
|
7164
|
+
this.setSelection(this.selection.slice(0, i).concat([target, next]), false);
|
|
7165
|
+
}
|
|
6873
7166
|
}
|
|
6874
|
-
}
|
|
7167
|
+
}
|
|
6875
7168
|
}
|
|
6876
|
-
else
|
|
6877
|
-
|
|
7169
|
+
else {
|
|
7170
|
+
if (target.run)
|
|
7171
|
+
target.run(this.wg);
|
|
7172
|
+
this.setSelection(this.children.includes(target) ? [target] : this.selection.length ? [this.selection[0]] : [], false);
|
|
6878
7173
|
}
|
|
7174
|
+
event.preventDefault();
|
|
6879
7175
|
}
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
mousemove(event) {
|
|
6886
|
-
this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
|
|
6887
|
-
if (this.hoverTimeout < 0)
|
|
6888
|
-
this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
|
|
6889
|
-
let { active, tooltip } = this;
|
|
6890
|
-
if (active.length && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
|
|
6891
|
-
let { pos } = active[0] || this.pending, end = active[0]?.end ?? pos;
|
|
6892
|
-
if ((pos == end ? this.wg.posAtCoords(this.lastMove).pos != pos
|
|
6893
|
-
: !isOverRange(this.wg, pos, end, event.clientX, event.clientY))) {
|
|
6894
|
-
this.wg.dispatch({ effects: this.setHover.of([]) });
|
|
6895
|
-
this.pending = null;
|
|
6896
|
-
}
|
|
7176
|
+
globalClick(event) {
|
|
7177
|
+
if (!event.composedPath().includes(this.dom)) {
|
|
7178
|
+
this.dom.ownerDocument.removeEventListener("mousedown", this.globalClick);
|
|
7179
|
+
if (this.selection.length > 1)
|
|
7180
|
+
this.setSelection([this.selection[0]], false);
|
|
6897
7181
|
}
|
|
6898
7182
|
}
|
|
6899
|
-
|
|
6900
|
-
clearTimeout(this.
|
|
6901
|
-
this.
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
7183
|
+
focusout() {
|
|
7184
|
+
clearTimeout(this.focusTimeout);
|
|
7185
|
+
if (this.selection.length > 1) {
|
|
7186
|
+
this.focusTimeout = setTimeout(() => {
|
|
7187
|
+
let active = this.wg.root.activeElement;
|
|
7188
|
+
for (let i = 0; i < this.selection.length - 1; i++) {
|
|
7189
|
+
if (!active || !this.selection[i].dom.contains(active)) {
|
|
7190
|
+
this.setSelection([this.selection[0]], false);
|
|
7191
|
+
break;
|
|
7192
|
+
}
|
|
7193
|
+
}
|
|
7194
|
+
}, 20);
|
|
6910
7195
|
}
|
|
6911
7196
|
}
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
if (this.active.length && !this.wg.dom.contains(event.relatedTarget))
|
|
6916
|
-
this.wg.dispatch({ effects: this.setHover.of([]) });
|
|
6917
|
-
};
|
|
6918
|
-
tooltip.addEventListener("mouseleave", watch);
|
|
7197
|
+
up() {
|
|
7198
|
+
if (this.selection.length > 1)
|
|
7199
|
+
this.setSelection([this.selection[0]], false);
|
|
6919
7200
|
}
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
7201
|
+
get top() { return true; }
|
|
7202
|
+
}
|
|
7203
|
+
const menuBarPanel = /*@__PURE__*/(() => Panel.show.of(MenuBar.create))();
|
|
7204
|
+
function findChild(children, start) {
|
|
7205
|
+
for (let i = start ? 0 : children.length - 1; start ? i < children.length : i >= 0; start ? i++ : i--) {
|
|
7206
|
+
let child = children[i];
|
|
7207
|
+
if (!(child.flags & 8))
|
|
7208
|
+
return child;
|
|
6924
7209
|
}
|
|
7210
|
+
return null;
|
|
6925
7211
|
}
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
7212
|
+
function findNextChild(children, child, dir) {
|
|
7213
|
+
let index = children.indexOf(child);
|
|
7214
|
+
if (index < 0)
|
|
7215
|
+
return null;
|
|
7216
|
+
for (let i = index + dir;; i += dir) {
|
|
7217
|
+
if (i < 0)
|
|
7218
|
+
i = children.length - 1;
|
|
7219
|
+
else if (i >= children.length)
|
|
7220
|
+
i = 0;
|
|
7221
|
+
if (i == index)
|
|
7222
|
+
return null;
|
|
7223
|
+
let child = children[i];
|
|
7224
|
+
if (!(child.flags & 32))
|
|
7225
|
+
return child;
|
|
6933
7226
|
}
|
|
6934
|
-
return event.clientX >= left - tooltipMargin && event.clientX <= right + tooltipMargin &&
|
|
6935
|
-
event.clientY >= top - tooltipMargin && event.clientY <= bottom + tooltipMargin;
|
|
6936
7227
|
}
|
|
6937
|
-
function
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
7228
|
+
function defaultChild(children) {
|
|
7229
|
+
return children.length ? children.find(ch => ch.flags & 16) || children[0] : null;
|
|
7230
|
+
}
|
|
7231
|
+
const theme = /*@__PURE__*/Wordgard.styles({
|
|
7232
|
+
"&": {
|
|
7233
|
+
"--wg-menu-item-size": "20px"
|
|
7234
|
+
},
|
|
7235
|
+
"&light": {
|
|
7236
|
+
"--wg-menu-color": "#555"
|
|
7237
|
+
},
|
|
7238
|
+
"&dark": {
|
|
7239
|
+
"--wg-menu-color": "#ccc"
|
|
7240
|
+
},
|
|
7241
|
+
"wg-menubar": {
|
|
7242
|
+
display: "flex",
|
|
7243
|
+
flexWrap: "wrap",
|
|
7244
|
+
gap: "5px",
|
|
7245
|
+
padding: "3px",
|
|
7246
|
+
color: "var(--wg-menu-color)",
|
|
7247
|
+
borderBottom: "1px solid var(--wg-border-color)",
|
|
7248
|
+
},
|
|
7249
|
+
".wg-menu-button:focus": {
|
|
7250
|
+
outline: "1.5px solid var(--wg-highlight-color)"
|
|
7251
|
+
},
|
|
7252
|
+
".wg-menu-button": {
|
|
7253
|
+
border: 0,
|
|
7254
|
+
padding: "3px",
|
|
7255
|
+
borderRadius: "4px",
|
|
7256
|
+
boxSizing: "content-box",
|
|
7257
|
+
backgroundColor: "transparent",
|
|
7258
|
+
font: "inherit",
|
|
7259
|
+
color: "inherit",
|
|
7260
|
+
height: "var(--wg-menu-item-size)",
|
|
7261
|
+
textAlign: "left",
|
|
7262
|
+
"&[aria-disabled]": {
|
|
7263
|
+
opacity: "0.3"
|
|
7264
|
+
},
|
|
7265
|
+
"&[aria-pressed]": {
|
|
7266
|
+
color: "var(--wg-highlight-color)"
|
|
7267
|
+
},
|
|
7268
|
+
"&:hover": {
|
|
7269
|
+
backgroundColor: "#88888820",
|
|
7270
|
+
},
|
|
7271
|
+
},
|
|
7272
|
+
".wg-button-label": {
|
|
7273
|
+
display: "inline-block",
|
|
7274
|
+
minWidth: "var(--wg-submenu-width)",
|
|
7275
|
+
padding: "0 3px",
|
|
7276
|
+
},
|
|
7277
|
+
"svg.wg-icon": {
|
|
7278
|
+
fill: "currentColor",
|
|
7279
|
+
width: "var(--wg-menu-item-size)",
|
|
7280
|
+
height: "var(--wg-menu-item-size)",
|
|
7281
|
+
},
|
|
7282
|
+
"wg-menu-spacer": {
|
|
7283
|
+
display: "block",
|
|
7284
|
+
width: "7px"
|
|
7285
|
+
},
|
|
7286
|
+
"wg-submenu": {
|
|
7287
|
+
display: "block",
|
|
7288
|
+
position: "relative",
|
|
7289
|
+
lineHeight: ".6",
|
|
7290
|
+
whiteSpace: "nowrap"
|
|
7291
|
+
},
|
|
7292
|
+
"wg-menu-list": {
|
|
7293
|
+
display: "flex",
|
|
7294
|
+
flexDirection: "column",
|
|
7295
|
+
alignItems: "stretch",
|
|
7296
|
+
gap: "5px",
|
|
7297
|
+
padding: "5px",
|
|
7298
|
+
borderRadius: "4px",
|
|
7299
|
+
backgroundColor: "var(--wg-panel-color)",
|
|
7300
|
+
position: "absolute",
|
|
7301
|
+
zIndex: "10",
|
|
7302
|
+
top: "100%",
|
|
7303
|
+
boxShadow: "0 2px 8px 0 rgba(128, 128, 128, 0.2)",
|
|
7304
|
+
"& wg-menu-list": {
|
|
7305
|
+
left: "100%",
|
|
7306
|
+
top: 0
|
|
7307
|
+
}
|
|
7308
|
+
},
|
|
7309
|
+
".wg-submenu-arrow:after": {
|
|
7310
|
+
padding: "0 2px",
|
|
7311
|
+
fontSize: "80%",
|
|
7312
|
+
verticalAlign: "10%",
|
|
7313
|
+
opacity: "0.4",
|
|
7314
|
+
content: "'▾'"
|
|
7315
|
+
},
|
|
7316
|
+
".wg-submenu-arrow.wg-submenu-arrow-open:after": {
|
|
7317
|
+
content: "'▴'"
|
|
7318
|
+
},
|
|
7319
|
+
});
|
|
7320
|
+
const barTemplate = /*@__PURE__*/GardState.Facet.define({
|
|
7321
|
+
combine: inputs => inputs.length ? inputs[0] : [Menu.Group.top.template()]
|
|
7322
|
+
});
|
|
7323
|
+
function menuBar(config = {}) {
|
|
7324
|
+
let extensions = [menuBarPanel, theme];
|
|
7325
|
+
if (config.template)
|
|
7326
|
+
extensions.push(barTemplate.of(Array.isArray(config.template) ? config.template : [config.template]));
|
|
7327
|
+
return extensions;
|
|
6943
7328
|
}
|
|
6944
7329
|
|
|
6945
7330
|
const inputRule = /*@__PURE__*/GardState.Facet.define();
|
|
@@ -7204,4 +7589,4 @@ function dropCursor() {
|
|
|
7204
7589
|
return [dropCursorPos, drawDropCursor];
|
|
7205
7590
|
}
|
|
7206
7591
|
|
|
7207
|
-
export { Decoration, Dialog, InputRule, KeyBinding, Panel, Tooltip, Widget, Wordgard, decoratePlots, dropCursor, menuBar, placeholder };
|
|
7592
|
+
export { Decoration, Dialog, InputRule, KeyBinding, Panel, PositioningHint, Tooltip, Widget, Wordgard, decoratePlots, dropCursor, keyBindingHelp, menuBar, placeholder };
|