prosemirror-view 1.31.1 → 1.31.3

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/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ## 1.31.3 (2023-05-17)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix an issue that could cause the clipboard parser to create invalid slices when parsing content containing isolating nodes.
6
+
7
+ Include CommonJS type declarations in the package to please new TypeScript resolution settings.
8
+
9
+ ## 1.31.2 (2023-05-10)
10
+
11
+ ### Bug fixes
12
+
13
+ Fix a bug that broke backspace after empty lines in code blocks on Firefox.
14
+
15
+ Make it possible for the `attributes` prop to override the `translate` attribute.
16
+
1
17
  ## 1.31.1 (2023-05-01)
2
18
 
3
19
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -1134,21 +1134,6 @@ var ViewDesc = function () {
1134
1134
 
1135
1135
  if (node.nodeType == 3) {
1136
1136
  brKludge = !!(_offset && node.nodeValue[_offset - 1] == "\n");
1137
-
1138
- if (brKludge && _offset == node.nodeValue.length) {
1139
- for (var scan = node, after; scan; scan = scan.parentNode) {
1140
- if (after = scan.nextSibling) {
1141
- if (after.nodeName == "BR") anchorDOM = headDOM = {
1142
- node: after.parentNode,
1143
- offset: domIndex(after) + 1
1144
- };
1145
- break;
1146
- }
1147
-
1148
- var desc = scan.pmViewDesc;
1149
- if (desc && desc.node && desc.node.isBlock) break;
1150
- }
1151
- }
1152
1137
  } else {
1153
1138
  var prev = node.childNodes[_offset - 1];
1154
1139
  brKludge = prev && (prev.nodeName == "BR" || prev.contentEditable == "false");
@@ -1156,8 +1141,8 @@ var ViewDesc = function () {
1156
1141
  }
1157
1142
 
1158
1143
  if (gecko && domSel.focusNode && domSel.focusNode != headDOM.node && domSel.focusNode.nodeType == 1) {
1159
- var _after2 = domSel.focusNode.childNodes[domSel.focusOffset];
1160
- if (_after2 && _after2.contentEditable == "false") force = true;
1144
+ var after = domSel.focusNode.childNodes[domSel.focusOffset];
1145
+ if (after && after.contentEditable == "false") force = true;
1161
1146
  }
1162
1147
 
1163
1148
  if (!(force || brKludge && safari) && isEquivalentPosition(anchorDOM.node, anchorDOM.offset, domSel.anchorNode, domSel.anchorOffset) && isEquivalentPosition(headDOM.node, headDOM.offset, domSel.focusNode, domSel.focusOffset)) return;
@@ -3234,8 +3219,9 @@ function closeRight(node, depth) {
3234
3219
  function closeRange(fragment, side, from, to, depth, openEnd) {
3235
3220
  var node = side < 0 ? fragment.firstChild : fragment.lastChild,
3236
3221
  inner = node.content;
3222
+ if (fragment.childCount > 1) openEnd = 0;
3237
3223
  if (depth < to - 1) inner = closeRange(inner, side, from, to, depth + 1, openEnd);
3238
- if (depth >= from) inner = side < 0 ? node.contentMatchAt(0).fillBefore(inner, fragment.childCount > 1 || openEnd <= depth).append(inner) : inner.append(node.contentMatchAt(node.childCount).fillBefore(prosemirrorModel.Fragment.empty, true));
3224
+ if (depth >= from) inner = side < 0 ? node.contentMatchAt(0).fillBefore(inner, openEnd <= depth).append(inner) : inner.append(node.contentMatchAt(node.childCount).fillBefore(prosemirrorModel.Fragment.empty, true));
3239
3225
  return fragment.replaceChild(side < 0 ? 0 : fragment.childCount - 1, node.copy(inner));
3240
3226
  }
3241
3227
 
@@ -5959,17 +5945,13 @@ function computeDocDeco(view) {
5959
5945
  var attrs = Object.create(null);
5960
5946
  attrs["class"] = "ProseMirror";
5961
5947
  attrs.contenteditable = String(view.editable);
5962
- attrs.translate = "no";
5963
5948
  view.someProp("attributes", function (value) {
5964
5949
  if (typeof value == "function") value = value(view.state);
5965
5950
  if (value) for (var attr in value) {
5966
- if (attr == "class") attrs["class"] += " " + value[attr];
5967
-
5968
- if (attr == "style") {
5969
- attrs.style = (attrs.style ? attrs.style + ";" : "") + value[attr];
5970
- } else if (!attrs[attr] && attr != "contenteditable" && attr != "nodeName") attrs[attr] = String(value[attr]);
5951
+ if (attr == "class") attrs["class"] += " " + value[attr];else if (attr == "style") attrs.style = (attrs.style ? attrs.style + ";" : "") + value[attr];else if (!attrs[attr] && attr != "contenteditable" && attr != "nodeName") attrs[attr] = String(value[attr]);
5971
5952
  }
5972
5953
  });
5954
+ if (!attrs.translate) attrs.translate = "no";
5973
5955
  return [Decoration.node(0, view.state.doc.content.size, attrs)];
5974
5956
  }
5975
5957
 
@@ -0,0 +1,898 @@
1
+ import { EditorState, Transaction, Selection, Plugin } from 'prosemirror-state';
2
+ import { Mark, Node, ParseRule, Slice, ResolvedPos, DOMParser, DOMSerializer } from 'prosemirror-model';
3
+ import { Mapping } from 'prosemirror-transform';
4
+
5
+ declare type DOMNode = InstanceType<typeof window.Node>;
6
+
7
+ declare type WidgetConstructor = ((view: EditorView, getPos: () => number | undefined) => DOMNode) | DOMNode;
8
+ /**
9
+ Decoration objects can be provided to the view through the
10
+ [`decorations` prop](https://prosemirror.net/docs/ref/#view.EditorProps.decorations). They come in
11
+ several variants—see the static members of this class for details.
12
+ */
13
+ declare class Decoration {
14
+ /**
15
+ The start position of the decoration.
16
+ */
17
+ readonly from: number;
18
+ /**
19
+ The end position. Will be the same as `from` for [widget
20
+ decorations](https://prosemirror.net/docs/ref/#view.Decoration^widget).
21
+ */
22
+ readonly to: number;
23
+ /**
24
+ Creates a widget decoration, which is a DOM node that's shown in
25
+ the document at the given position. It is recommended that you
26
+ delay rendering the widget by passing a function that will be
27
+ called when the widget is actually drawn in a view, but you can
28
+ also directly pass a DOM node. `getPos` can be used to find the
29
+ widget's current document position.
30
+ */
31
+ static widget(pos: number, toDOM: WidgetConstructor, spec?: {
32
+ /**
33
+ Controls which side of the document position this widget is
34
+ associated with. When negative, it is drawn before a cursor
35
+ at its position, and content inserted at that position ends
36
+ up after the widget. When zero (the default) or positive, the
37
+ widget is drawn after the cursor and content inserted there
38
+ ends up before the widget.
39
+
40
+ When there are multiple widgets at a given position, their
41
+ `side` values determine the order in which they appear. Those
42
+ with lower values appear first. The ordering of widgets with
43
+ the same `side` value is unspecified.
44
+
45
+ When `marks` is null, `side` also determines the marks that
46
+ the widget is wrapped in—those of the node before when
47
+ negative, those of the node after when positive.
48
+ */
49
+ side?: number;
50
+ /**
51
+ The precise set of marks to draw around the widget.
52
+ */
53
+ marks?: readonly Mark[];
54
+ /**
55
+ Can be used to control which DOM events, when they bubble out
56
+ of this widget, the editor view should ignore.
57
+ */
58
+ stopEvent?: (event: Event) => boolean;
59
+ /**
60
+ When set (defaults to false), selection changes inside the
61
+ widget are ignored, and don't cause ProseMirror to try and
62
+ re-sync the selection with its selection state.
63
+ */
64
+ ignoreSelection?: boolean;
65
+ /**
66
+ When comparing decorations of this type (in order to decide
67
+ whether it needs to be redrawn), ProseMirror will by default
68
+ compare the widget DOM node by identity. If you pass a key,
69
+ that key will be compared instead, which can be useful when
70
+ you generate decorations on the fly and don't want to store
71
+ and reuse DOM nodes. Make sure that any widgets with the same
72
+ key are interchangeable—if widgets differ in, for example,
73
+ the behavior of some event handler, they should get
74
+ different keys.
75
+ */
76
+ key?: string;
77
+ /**
78
+ Called when the widget decoration is removed as a result of
79
+ mapping
80
+ */
81
+ destroy?: (node: DOMNode) => void;
82
+ /**
83
+ Specs allow arbitrary additional properties.
84
+ */
85
+ [key: string]: any;
86
+ }): Decoration;
87
+ /**
88
+ Creates an inline decoration, which adds the given attributes to
89
+ each inline node between `from` and `to`.
90
+ */
91
+ static inline(from: number, to: number, attrs: DecorationAttrs, spec?: {
92
+ /**
93
+ Determines how the left side of the decoration is
94
+ [mapped](https://prosemirror.net/docs/ref/#transform.Position_Mapping) when content is
95
+ inserted directly at that position. By default, the decoration
96
+ won't include the new content, but you can set this to `true`
97
+ to make it inclusive.
98
+ */
99
+ inclusiveStart?: boolean;
100
+ /**
101
+ Determines how the right side of the decoration is mapped.
102
+ See
103
+ [`inclusiveStart`](https://prosemirror.net/docs/ref/#view.Decoration^inline^spec.inclusiveStart).
104
+ */
105
+ inclusiveEnd?: boolean;
106
+ /**
107
+ Specs may have arbitrary additional properties.
108
+ */
109
+ [key: string]: any;
110
+ }): Decoration;
111
+ /**
112
+ Creates a node decoration. `from` and `to` should point precisely
113
+ before and after a node in the document. That node, and only that
114
+ node, will receive the given attributes.
115
+ */
116
+ static node(from: number, to: number, attrs: DecorationAttrs, spec?: any): Decoration;
117
+ /**
118
+ The spec provided when creating this decoration. Can be useful
119
+ if you've stored extra information in that object.
120
+ */
121
+ get spec(): any;
122
+ }
123
+ /**
124
+ A set of attributes to add to a decorated node. Most properties
125
+ simply directly correspond to DOM attributes of the same name,
126
+ which will be set to the property's value. These are exceptions:
127
+ */
128
+ declare type DecorationAttrs = {
129
+ /**
130
+ When non-null, the target node is wrapped in a DOM element of
131
+ this type (and the other attributes are applied to this element).
132
+ */
133
+ nodeName?: string;
134
+ /**
135
+ A CSS class name or a space-separated set of class names to be
136
+ _added_ to the classes that the node already had.
137
+ */
138
+ class?: string;
139
+ /**
140
+ A string of CSS to be _added_ to the node's existing `style` property.
141
+ */
142
+ style?: string;
143
+ /**
144
+ Any other properties are treated as regular DOM attributes.
145
+ */
146
+ [attribute: string]: string | undefined;
147
+ };
148
+ /**
149
+ An object that can [provide](https://prosemirror.net/docs/ref/#view.EditorProps.decorations)
150
+ decorations. Implemented by [`DecorationSet`](https://prosemirror.net/docs/ref/#view.DecorationSet),
151
+ and passed to [node views](https://prosemirror.net/docs/ref/#view.EditorProps.nodeViews).
152
+ */
153
+ interface DecorationSource {
154
+ /**
155
+ Map the set of decorations in response to a change in the
156
+ document.
157
+ */
158
+ map: (mapping: Mapping, node: Node) => DecorationSource;
159
+ }
160
+ /**
161
+ A collection of [decorations](https://prosemirror.net/docs/ref/#view.Decoration), organized in such
162
+ a way that the drawing algorithm can efficiently use and compare
163
+ them. This is a persistent data structure—it is not modified,
164
+ updates create a new value.
165
+ */
166
+ declare class DecorationSet implements DecorationSource {
167
+ /**
168
+ Create a set of decorations, using the structure of the given
169
+ document.
170
+ */
171
+ static create(doc: Node, decorations: Decoration[]): DecorationSet;
172
+ /**
173
+ Find all decorations in this set which touch the given range
174
+ (including decorations that start or end directly at the
175
+ boundaries) and match the given predicate on their spec. When
176
+ `start` and `end` are omitted, all decorations in the set are
177
+ considered. When `predicate` isn't given, all decorations are
178
+ assumed to match.
179
+ */
180
+ find(start?: number, end?: number, predicate?: (spec: any) => boolean): Decoration[];
181
+ private findInner;
182
+ /**
183
+ Map the set of decorations in response to a change in the
184
+ document.
185
+ */
186
+ map(mapping: Mapping, doc: Node, options?: {
187
+ /**
188
+ When given, this function will be called for each decoration
189
+ that gets dropped as a result of the mapping, passing the
190
+ spec of that decoration.
191
+ */
192
+ onRemove?: (decorationSpec: any) => void;
193
+ }): DecorationSet;
194
+ /**
195
+ Add the given array of decorations to the ones in the set,
196
+ producing a new set. Needs access to the current document to
197
+ create the appropriate tree structure.
198
+ */
199
+ add(doc: Node, decorations: Decoration[]): DecorationSet;
200
+ private addInner;
201
+ /**
202
+ Create a new set that contains the decorations in this set, minus
203
+ the ones in the given array.
204
+ */
205
+ remove(decorations: Decoration[]): DecorationSet;
206
+ private removeInner;
207
+ /**
208
+ The empty set of decorations.
209
+ */
210
+ static empty: DecorationSet;
211
+ }
212
+
213
+ declare global {
214
+ interface Node {
215
+ pmViewDesc?: ViewDesc;
216
+ }
217
+ }
218
+ /**
219
+ By default, document nodes are rendered using the result of the
220
+ [`toDOM`](https://prosemirror.net/docs/ref/#model.NodeSpec.toDOM) method of their spec, and managed
221
+ entirely by the editor. For some use cases, such as embedded
222
+ node-specific editing interfaces, you want more control over
223
+ the behavior of a node's in-editor representation, and need to
224
+ [define](https://prosemirror.net/docs/ref/#view.EditorProps.nodeViews) a custom node view.
225
+
226
+ Mark views only support `dom` and `contentDOM`, and don't support
227
+ any of the node view methods.
228
+
229
+ Objects returned as node views must conform to this interface.
230
+ */
231
+ interface NodeView {
232
+ /**
233
+ The outer DOM node that represents the document node.
234
+ */
235
+ dom: DOMNode;
236
+ /**
237
+ The DOM node that should hold the node's content. Only meaningful
238
+ if the node view also defines a `dom` property and if its node
239
+ type is not a leaf node type. When this is present, ProseMirror
240
+ will take care of rendering the node's children into it. When it
241
+ is not present, the node view itself is responsible for rendering
242
+ (or deciding not to render) its child nodes.
243
+ */
244
+ contentDOM?: HTMLElement | null;
245
+ /**
246
+ When given, this will be called when the view is updating itself.
247
+ It will be given a node (possibly of a different type), an array
248
+ of active decorations around the node (which are automatically
249
+ drawn, and the node view may ignore if it isn't interested in
250
+ them), and a [decoration source](https://prosemirror.net/docs/ref/#view.DecorationSource) that
251
+ represents any decorations that apply to the content of the node
252
+ (which again may be ignored). It should return true if it was
253
+ able to update to that node, and false otherwise. If the node
254
+ view has a `contentDOM` property (or no `dom` property), updating
255
+ its child nodes will be handled by ProseMirror.
256
+ */
257
+ update?: (node: Node, decorations: readonly Decoration[], innerDecorations: DecorationSource) => boolean;
258
+ /**
259
+ Can be used to override the way the node's selected status (as a
260
+ node selection) is displayed.
261
+ */
262
+ selectNode?: () => void;
263
+ /**
264
+ When defining a `selectNode` method, you should also provide a
265
+ `deselectNode` method to remove the effect again.
266
+ */
267
+ deselectNode?: () => void;
268
+ /**
269
+ This will be called to handle setting the selection inside the
270
+ node. The `anchor` and `head` positions are relative to the start
271
+ of the node. By default, a DOM selection will be created between
272
+ the DOM positions corresponding to those positions, but if you
273
+ override it you can do something else.
274
+ */
275
+ setSelection?: (anchor: number, head: number, root: Document | ShadowRoot) => void;
276
+ /**
277
+ Can be used to prevent the editor view from trying to handle some
278
+ or all DOM events that bubble up from the node view. Events for
279
+ which this returns true are not handled by the editor.
280
+ */
281
+ stopEvent?: (event: Event) => boolean;
282
+ /**
283
+ Called when a DOM
284
+ [mutation](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)
285
+ or a selection change happens within the view. When the change is
286
+ a selection change, the record will have a `type` property of
287
+ `"selection"` (which doesn't occur for native mutation records).
288
+ Return false if the editor should re-read the selection or
289
+ re-parse the range around the mutation, true if it can safely be
290
+ ignored.
291
+ */
292
+ ignoreMutation?: (mutation: MutationRecord) => boolean;
293
+ /**
294
+ Called when the node view is removed from the editor or the whole
295
+ editor is destroyed. (Not available for marks.)
296
+ */
297
+ destroy?: () => void;
298
+ }
299
+ declare class ViewDesc {
300
+ parent: ViewDesc | undefined;
301
+ children: ViewDesc[];
302
+ dom: DOMNode;
303
+ contentDOM: HTMLElement | null;
304
+ dirty: number;
305
+ node: Node | null;
306
+ constructor(parent: ViewDesc | undefined, children: ViewDesc[], dom: DOMNode, contentDOM: HTMLElement | null);
307
+ matchesWidget(widget: Decoration): boolean;
308
+ matchesMark(mark: Mark): boolean;
309
+ matchesNode(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource): boolean;
310
+ matchesHack(nodeName: string): boolean;
311
+ parseRule(): ParseRule | null;
312
+ stopEvent(event: Event): boolean;
313
+ get size(): number;
314
+ get border(): number;
315
+ destroy(): void;
316
+ posBeforeChild(child: ViewDesc): number;
317
+ get posBefore(): number;
318
+ get posAtStart(): number;
319
+ get posAfter(): number;
320
+ get posAtEnd(): number;
321
+ localPosFromDOM(dom: DOMNode, offset: number, bias: number): number;
322
+ nearestDesc(dom: DOMNode): ViewDesc | undefined;
323
+ nearestDesc(dom: DOMNode, onlyNodes: true): NodeViewDesc | undefined;
324
+ getDesc(dom: DOMNode): ViewDesc | undefined;
325
+ posFromDOM(dom: DOMNode, offset: number, bias: number): number;
326
+ descAt(pos: number): ViewDesc | undefined;
327
+ domFromPos(pos: number, side: number): {
328
+ node: DOMNode;
329
+ offset: number;
330
+ atom?: number;
331
+ };
332
+ parseRange(from: number, to: number, base?: number): {
333
+ node: DOMNode;
334
+ from: number;
335
+ to: number;
336
+ fromOffset: number;
337
+ toOffset: number;
338
+ };
339
+ emptyChildAt(side: number): boolean;
340
+ domAfterPos(pos: number): DOMNode;
341
+ setSelection(anchor: number, head: number, root: Document | ShadowRoot, force?: boolean): void;
342
+ ignoreMutation(mutation: MutationRecord): boolean;
343
+ get contentLost(): boolean | null;
344
+ markDirty(from: number, to: number): void;
345
+ markParentsDirty(): void;
346
+ get domAtom(): boolean;
347
+ get ignoreForCoords(): boolean;
348
+ }
349
+ declare class NodeViewDesc extends ViewDesc {
350
+ node: Node;
351
+ outerDeco: readonly Decoration[];
352
+ innerDeco: DecorationSource;
353
+ readonly nodeDOM: DOMNode;
354
+ constructor(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, dom: DOMNode, contentDOM: HTMLElement | null, nodeDOM: DOMNode, view: EditorView, pos: number);
355
+ static create(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView, pos: number): NodeViewDesc | TextViewDesc;
356
+ parseRule(): ParseRule | null;
357
+ matchesNode(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource): boolean;
358
+ get size(): number;
359
+ get border(): 1 | 0;
360
+ updateChildren(view: EditorView, pos: number): void;
361
+ localCompositionInfo(view: EditorView, pos: number): {
362
+ node: Text;
363
+ pos: number;
364
+ text: string;
365
+ } | null;
366
+ protectLocalComposition(view: EditorView, { node, pos, text }: {
367
+ node: Text;
368
+ pos: number;
369
+ text: string;
370
+ }): void;
371
+ update(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView): boolean;
372
+ updateInner(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView): void;
373
+ updateOuterDeco(outerDeco: readonly Decoration[]): void;
374
+ selectNode(): void;
375
+ deselectNode(): void;
376
+ get domAtom(): boolean;
377
+ }
378
+ declare class TextViewDesc extends NodeViewDesc {
379
+ constructor(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, dom: DOMNode, nodeDOM: DOMNode, view: EditorView);
380
+ parseRule(): ParseRule;
381
+ update(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView): boolean;
382
+ inParent(): boolean;
383
+ domFromPos(pos: number): {
384
+ node: globalThis.Node;
385
+ offset: number;
386
+ };
387
+ localPosFromDOM(dom: DOMNode, offset: number, bias: number): number;
388
+ ignoreMutation(mutation: MutationRecord): boolean;
389
+ slice(from: number, to: number, view: EditorView): TextViewDesc;
390
+ markDirty(from: number, to: number): void;
391
+ get domAtom(): boolean;
392
+ }
393
+
394
+ /**
395
+ An editor view manages the DOM structure that represents an
396
+ editable document. Its state and behavior are determined by its
397
+ [props](https://prosemirror.net/docs/ref/#view.DirectEditorProps).
398
+ */
399
+ declare class EditorView {
400
+ private _props;
401
+ private directPlugins;
402
+ private _root;
403
+ private mounted;
404
+ private prevDirectPlugins;
405
+ private pluginViews;
406
+ /**
407
+ The view's current [state](https://prosemirror.net/docs/ref/#state.EditorState).
408
+ */
409
+ state: EditorState;
410
+ /**
411
+ Create a view. `place` may be a DOM node that the editor should
412
+ be appended to, a function that will place it into the document,
413
+ or an object whose `mount` property holds the node to use as the
414
+ document container. If it is `null`, the editor will not be
415
+ added to the document.
416
+ */
417
+ constructor(place: null | DOMNode | ((editor: HTMLElement) => void) | {
418
+ mount: HTMLElement;
419
+ }, props: DirectEditorProps);
420
+ /**
421
+ An editable DOM node containing the document. (You probably
422
+ should not directly interfere with its content.)
423
+ */
424
+ readonly dom: HTMLElement;
425
+ /**
426
+ Indicates whether the editor is currently [editable](https://prosemirror.net/docs/ref/#view.EditorProps.editable).
427
+ */
428
+ editable: boolean;
429
+ /**
430
+ When editor content is being dragged, this object contains
431
+ information about the dragged slice and whether it is being
432
+ copied or moved. At any other time, it is null.
433
+ */
434
+ dragging: null | {
435
+ slice: Slice;
436
+ move: boolean;
437
+ };
438
+ /**
439
+ Holds `true` when a
440
+ [composition](https://w3c.github.io/uievents/#events-compositionevents)
441
+ is active.
442
+ */
443
+ get composing(): boolean;
444
+ /**
445
+ The view's current [props](https://prosemirror.net/docs/ref/#view.EditorProps).
446
+ */
447
+ get props(): DirectEditorProps;
448
+ /**
449
+ Update the view's props. Will immediately cause an update to
450
+ the DOM.
451
+ */
452
+ update(props: DirectEditorProps): void;
453
+ /**
454
+ Update the view by updating existing props object with the object
455
+ given as argument. Equivalent to `view.update(Object.assign({},
456
+ view.props, props))`.
457
+ */
458
+ setProps(props: Partial<DirectEditorProps>): void;
459
+ /**
460
+ Update the editor's `state` prop, without touching any of the
461
+ other props.
462
+ */
463
+ updateState(state: EditorState): void;
464
+ private updateStateInner;
465
+ private destroyPluginViews;
466
+ private updatePluginViews;
467
+ /**
468
+ Goes over the values of a prop, first those provided directly,
469
+ then those from plugins given to the view, then from plugins in
470
+ the state (in order), and calls `f` every time a non-undefined
471
+ value is found. When `f` returns a truthy value, that is
472
+ immediately returned. When `f` isn't provided, it is treated as
473
+ the identity function (the prop value is returned directly).
474
+ */
475
+ someProp<PropName extends keyof EditorProps, Result>(propName: PropName, f: (value: NonNullable<EditorProps[PropName]>) => Result): Result | undefined;
476
+ someProp<PropName extends keyof EditorProps>(propName: PropName): NonNullable<EditorProps[PropName]> | undefined;
477
+ /**
478
+ Query whether the view has focus.
479
+ */
480
+ hasFocus(): boolean;
481
+ /**
482
+ Focus the editor.
483
+ */
484
+ focus(): void;
485
+ /**
486
+ Get the document root in which the editor exists. This will
487
+ usually be the top-level `document`, but might be a [shadow
488
+ DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
489
+ root if the editor is inside one.
490
+ */
491
+ get root(): Document | ShadowRoot;
492
+ /**
493
+ Given a pair of viewport coordinates, return the document
494
+ position that corresponds to them. May return null if the given
495
+ coordinates aren't inside of the editor. When an object is
496
+ returned, its `pos` property is the position nearest to the
497
+ coordinates, and its `inside` property holds the position of the
498
+ inner node that the position falls inside of, or -1 if it is at
499
+ the top level, not in any node.
500
+ */
501
+ posAtCoords(coords: {
502
+ left: number;
503
+ top: number;
504
+ }): {
505
+ pos: number;
506
+ inside: number;
507
+ } | null;
508
+ /**
509
+ Returns the viewport rectangle at a given document position.
510
+ `left` and `right` will be the same number, as this returns a
511
+ flat cursor-ish rectangle. If the position is between two things
512
+ that aren't directly adjacent, `side` determines which element
513
+ is used. When < 0, the element before the position is used,
514
+ otherwise the element after.
515
+ */
516
+ coordsAtPos(pos: number, side?: number): {
517
+ left: number;
518
+ right: number;
519
+ top: number;
520
+ bottom: number;
521
+ };
522
+ /**
523
+ Find the DOM position that corresponds to the given document
524
+ position. When `side` is negative, find the position as close as
525
+ possible to the content before the position. When positive,
526
+ prefer positions close to the content after the position. When
527
+ zero, prefer as shallow a position as possible.
528
+
529
+ Note that you should **not** mutate the editor's internal DOM,
530
+ only inspect it (and even that is usually not necessary).
531
+ */
532
+ domAtPos(pos: number, side?: number): {
533
+ node: DOMNode;
534
+ offset: number;
535
+ };
536
+ /**
537
+ Find the DOM node that represents the document node after the
538
+ given position. May return `null` when the position doesn't point
539
+ in front of a node or if the node is inside an opaque node view.
540
+
541
+ This is intended to be able to call things like
542
+ `getBoundingClientRect` on that DOM node. Do **not** mutate the
543
+ editor DOM directly, or add styling this way, since that will be
544
+ immediately overriden by the editor as it redraws the node.
545
+ */
546
+ nodeDOM(pos: number): DOMNode | null;
547
+ /**
548
+ Find the document position that corresponds to a given DOM
549
+ position. (Whenever possible, it is preferable to inspect the
550
+ document structure directly, rather than poking around in the
551
+ DOM, but sometimes—for example when interpreting an event
552
+ target—you don't have a choice.)
553
+
554
+ The `bias` parameter can be used to influence which side of a DOM
555
+ node to use when the position is inside a leaf node.
556
+ */
557
+ posAtDOM(node: DOMNode, offset: number, bias?: number): number;
558
+ /**
559
+ Find out whether the selection is at the end of a textblock when
560
+ moving in a given direction. When, for example, given `"left"`,
561
+ it will return true if moving left from the current cursor
562
+ position would leave that position's parent textblock. Will apply
563
+ to the view's current state by default, but it is possible to
564
+ pass a different state.
565
+ */
566
+ endOfTextblock(dir: "up" | "down" | "left" | "right" | "forward" | "backward", state?: EditorState): boolean;
567
+ /**
568
+ Run the editor's paste logic with the given HTML string. The
569
+ `event`, if given, will be passed to the
570
+ [`handlePaste`](https://prosemirror.net/docs/ref/#view.EditorProps.handlePaste) hook.
571
+ */
572
+ pasteHTML(html: string, event?: ClipboardEvent): boolean;
573
+ /**
574
+ Run the editor's paste logic with the given plain-text input.
575
+ */
576
+ pasteText(text: string, event?: ClipboardEvent): boolean;
577
+ /**
578
+ Removes the editor from the DOM and destroys all [node
579
+ views](https://prosemirror.net/docs/ref/#view.NodeView).
580
+ */
581
+ destroy(): void;
582
+ /**
583
+ This is true when the view has been
584
+ [destroyed](https://prosemirror.net/docs/ref/#view.EditorView.destroy) (and thus should not be
585
+ used anymore).
586
+ */
587
+ get isDestroyed(): boolean;
588
+ /**
589
+ Used for testing.
590
+ */
591
+ dispatchEvent(event: Event): void;
592
+ /**
593
+ Dispatch a transaction. Will call
594
+ [`dispatchTransaction`](https://prosemirror.net/docs/ref/#view.DirectEditorProps.dispatchTransaction)
595
+ when given, and otherwise defaults to applying the transaction to
596
+ the current state and calling
597
+ [`updateState`](https://prosemirror.net/docs/ref/#view.EditorView.updateState) with the result.
598
+ This method is bound to the view instance, so that it can be
599
+ easily passed around.
600
+ */
601
+ dispatch(tr: Transaction): void;
602
+ }
603
+ /**
604
+ The type of function [provided](https://prosemirror.net/docs/ref/#view.EditorProps.nodeViews) to
605
+ create [node views](https://prosemirror.net/docs/ref/#view.NodeView).
606
+ */
607
+ declare type NodeViewConstructor = (node: Node, view: EditorView, getPos: () => number | undefined, decorations: readonly Decoration[], innerDecorations: DecorationSource) => NodeView;
608
+ /**
609
+ The function types [used](https://prosemirror.net/docs/ref/#view.EditorProps.markViews) to create
610
+ mark views.
611
+ */
612
+ declare type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) => {
613
+ dom: HTMLElement;
614
+ contentDOM?: HTMLElement;
615
+ };
616
+ /**
617
+ Helper type that maps event names to event object types, but
618
+ includes events that TypeScript's HTMLElementEventMap doesn't know
619
+ about.
620
+ */
621
+ interface DOMEventMap extends HTMLElementEventMap {
622
+ [event: string]: any;
623
+ }
624
+ /**
625
+ Props are configuration values that can be passed to an editor view
626
+ or included in a plugin. This interface lists the supported props.
627
+
628
+ The various event-handling functions may all return `true` to
629
+ indicate that they handled the given event. The view will then take
630
+ care to call `preventDefault` on the event, except with
631
+ `handleDOMEvents`, where the handler itself is responsible for that.
632
+
633
+ How a prop is resolved depends on the prop. Handler functions are
634
+ called one at a time, starting with the base props and then
635
+ searching through the plugins (in order of appearance) until one of
636
+ them returns true. For some props, the first plugin that yields a
637
+ value gets precedence.
638
+
639
+ The optional type parameter refers to the type of `this` in prop
640
+ functions, and is used to pass in the plugin type when defining a
641
+ [plugin](https://prosemirror.net/docs/ref/#state.Plugin).
642
+ */
643
+ interface EditorProps<P = any> {
644
+ /**
645
+ Can be an object mapping DOM event type names to functions that
646
+ handle them. Such functions will be called before any handling
647
+ ProseMirror does of events fired on the editable DOM element.
648
+ Contrary to the other event handling props, when returning true
649
+ from such a function, you are responsible for calling
650
+ `preventDefault` yourself (or not, if you want to allow the
651
+ default behavior).
652
+ */
653
+ handleDOMEvents?: {
654
+ [event in keyof DOMEventMap]?: (this: P, view: EditorView, event: DOMEventMap[event]) => boolean | void;
655
+ };
656
+ /**
657
+ Called when the editor receives a `keydown` event.
658
+ */
659
+ handleKeyDown?: (this: P, view: EditorView, event: KeyboardEvent) => boolean | void;
660
+ /**
661
+ Handler for `keypress` events.
662
+ */
663
+ handleKeyPress?: (this: P, view: EditorView, event: KeyboardEvent) => boolean | void;
664
+ /**
665
+ Whenever the user directly input text, this handler is called
666
+ before the input is applied. If it returns `true`, the default
667
+ behavior of actually inserting the text is suppressed.
668
+ */
669
+ handleTextInput?: (this: P, view: EditorView, from: number, to: number, text: string) => boolean | void;
670
+ /**
671
+ Called for each node around a click, from the inside out. The
672
+ `direct` flag will be true for the inner node.
673
+ */
674
+ handleClickOn?: (this: P, view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void;
675
+ /**
676
+ Called when the editor is clicked, after `handleClickOn` handlers
677
+ have been called.
678
+ */
679
+ handleClick?: (this: P, view: EditorView, pos: number, event: MouseEvent) => boolean | void;
680
+ /**
681
+ Called for each node around a double click.
682
+ */
683
+ handleDoubleClickOn?: (this: P, view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void;
684
+ /**
685
+ Called when the editor is double-clicked, after `handleDoubleClickOn`.
686
+ */
687
+ handleDoubleClick?: (this: P, view: EditorView, pos: number, event: MouseEvent) => boolean | void;
688
+ /**
689
+ Called for each node around a triple click.
690
+ */
691
+ handleTripleClickOn?: (this: P, view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void;
692
+ /**
693
+ Called when the editor is triple-clicked, after `handleTripleClickOn`.
694
+ */
695
+ handleTripleClick?: (this: P, view: EditorView, pos: number, event: MouseEvent) => boolean | void;
696
+ /**
697
+ Can be used to override the behavior of pasting. `slice` is the
698
+ pasted content parsed by the editor, but you can directly access
699
+ the event to get at the raw content.
700
+ */
701
+ handlePaste?: (this: P, view: EditorView, event: ClipboardEvent, slice: Slice) => boolean | void;
702
+ /**
703
+ Called when something is dropped on the editor. `moved` will be
704
+ true if this drop moves from the current selection (which should
705
+ thus be deleted).
706
+ */
707
+ handleDrop?: (this: P, view: EditorView, event: DragEvent, slice: Slice, moved: boolean) => boolean | void;
708
+ /**
709
+ Called when the view, after updating its state, tries to scroll
710
+ the selection into view. A handler function may return false to
711
+ indicate that it did not handle the scrolling and further
712
+ handlers or the default behavior should be tried.
713
+ */
714
+ handleScrollToSelection?: (this: P, view: EditorView) => boolean;
715
+ /**
716
+ Can be used to override the way a selection is created when
717
+ reading a DOM selection between the given anchor and head.
718
+ */
719
+ createSelectionBetween?: (this: P, view: EditorView, anchor: ResolvedPos, head: ResolvedPos) => Selection | null;
720
+ /**
721
+ The [parser](https://prosemirror.net/docs/ref/#model.DOMParser) to use when reading editor changes
722
+ from the DOM. Defaults to calling
723
+ [`DOMParser.fromSchema`](https://prosemirror.net/docs/ref/#model.DOMParser^fromSchema) on the
724
+ editor's schema.
725
+ */
726
+ domParser?: DOMParser;
727
+ /**
728
+ Can be used to transform pasted HTML text, _before_ it is parsed,
729
+ for example to clean it up.
730
+ */
731
+ transformPastedHTML?: (this: P, html: string, view: EditorView) => string;
732
+ /**
733
+ The [parser](https://prosemirror.net/docs/ref/#model.DOMParser) to use when reading content from
734
+ the clipboard. When not given, the value of the
735
+ [`domParser`](https://prosemirror.net/docs/ref/#view.EditorProps.domParser) prop is used.
736
+ */
737
+ clipboardParser?: DOMParser;
738
+ /**
739
+ Transform pasted plain text. The `plain` flag will be true when
740
+ the text is pasted as plain text.
741
+ */
742
+ transformPastedText?: (this: P, text: string, plain: boolean, view: EditorView) => string;
743
+ /**
744
+ A function to parse text from the clipboard into a document
745
+ slice. Called after
746
+ [`transformPastedText`](https://prosemirror.net/docs/ref/#view.EditorProps.transformPastedText).
747
+ The default behavior is to split the text into lines, wrap them
748
+ in `<p>` tags, and call
749
+ [`clipboardParser`](https://prosemirror.net/docs/ref/#view.EditorProps.clipboardParser) on it.
750
+ The `plain` flag will be true when the text is pasted as plain text.
751
+ */
752
+ clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean, view: EditorView) => Slice;
753
+ /**
754
+ Can be used to transform pasted or dragged-and-dropped content
755
+ before it is applied to the document.
756
+ */
757
+ transformPasted?: (this: P, slice: Slice, view: EditorView) => Slice;
758
+ /**
759
+ Can be used to transform copied or cut content before it is
760
+ serialized to the clipboard.
761
+ */
762
+ transformCopied?: (this: P, slice: Slice, view: EditorView) => Slice;
763
+ /**
764
+ Allows you to pass custom rendering and behavior logic for
765
+ nodes. Should map node names to constructor functions that
766
+ produce a [`NodeView`](https://prosemirror.net/docs/ref/#view.NodeView) object implementing the
767
+ node's display behavior. The third argument `getPos` is a
768
+ function that can be called to get the node's current position,
769
+ which can be useful when creating transactions to update it.
770
+ Note that if the node is not in the document, the position
771
+ returned by this function will be `undefined`.
772
+
773
+ `decorations` is an array of node or inline decorations that are
774
+ active around the node. They are automatically drawn in the
775
+ normal way, and you will usually just want to ignore this, but
776
+ they can also be used as a way to provide context information to
777
+ the node view without adding it to the document itself.
778
+
779
+ `innerDecorations` holds the decorations for the node's content.
780
+ You can safely ignore this if your view has no content or a
781
+ `contentDOM` property, since the editor will draw the decorations
782
+ on the content. But if you, for example, want to create a nested
783
+ editor with the content, it may make sense to provide it with the
784
+ inner decorations.
785
+
786
+ (For backwards compatibility reasons, [mark
787
+ views](https://prosemirror.net/docs/ref/#view.EditorProps.markViews) can also be included in this
788
+ object.)
789
+ */
790
+ nodeViews?: {
791
+ [node: string]: NodeViewConstructor;
792
+ };
793
+ /**
794
+ Pass custom mark rendering functions. Note that these cannot
795
+ provide the kind of dynamic behavior that [node
796
+ views](https://prosemirror.net/docs/ref/#view.NodeView) can—they just provide custom rendering
797
+ logic. The third argument indicates whether the mark's content
798
+ is inline.
799
+ */
800
+ markViews?: {
801
+ [mark: string]: MarkViewConstructor;
802
+ };
803
+ /**
804
+ The DOM serializer to use when putting content onto the
805
+ clipboard. If not given, the result of
806
+ [`DOMSerializer.fromSchema`](https://prosemirror.net/docs/ref/#model.DOMSerializer^fromSchema)
807
+ will be used. This object will only have its
808
+ [`serializeFragment`](https://prosemirror.net/docs/ref/#model.DOMSerializer.serializeFragment)
809
+ method called, and you may provide an alternative object type
810
+ implementing a compatible method.
811
+ */
812
+ clipboardSerializer?: DOMSerializer;
813
+ /**
814
+ A function that will be called to get the text for the current
815
+ selection when copying text to the clipboard. By default, the
816
+ editor will use [`textBetween`](https://prosemirror.net/docs/ref/#model.Node.textBetween) on the
817
+ selected range.
818
+ */
819
+ clipboardTextSerializer?: (this: P, content: Slice, view: EditorView) => string;
820
+ /**
821
+ A set of [document decorations](https://prosemirror.net/docs/ref/#view.Decoration) to show in the
822
+ view.
823
+ */
824
+ decorations?: (this: P, state: EditorState) => DecorationSource | null | undefined;
825
+ /**
826
+ When this returns false, the content of the view is not directly
827
+ editable.
828
+ */
829
+ editable?: (this: P, state: EditorState) => boolean;
830
+ /**
831
+ Control the DOM attributes of the editable element. May be either
832
+ an object or a function going from an editor state to an object.
833
+ By default, the element will get a class `"ProseMirror"`, and
834
+ will have its `contentEditable` attribute determined by the
835
+ [`editable` prop](https://prosemirror.net/docs/ref/#view.EditorProps.editable). Additional classes
836
+ provided here will be added to the class. For other attributes,
837
+ the value provided first (as in
838
+ [`someProp`](https://prosemirror.net/docs/ref/#view.EditorView.someProp)) will be used.
839
+ */
840
+ attributes?: {
841
+ [name: string]: string;
842
+ } | ((state: EditorState) => {
843
+ [name: string]: string;
844
+ });
845
+ /**
846
+ Determines the distance (in pixels) between the cursor and the
847
+ end of the visible viewport at which point, when scrolling the
848
+ cursor into view, scrolling takes place. Defaults to 0.
849
+ */
850
+ scrollThreshold?: number | {
851
+ top: number;
852
+ right: number;
853
+ bottom: number;
854
+ left: number;
855
+ };
856
+ /**
857
+ Determines the extra space (in pixels) that is left above or
858
+ below the cursor when it is scrolled into view. Defaults to 5.
859
+ */
860
+ scrollMargin?: number | {
861
+ top: number;
862
+ right: number;
863
+ bottom: number;
864
+ left: number;
865
+ };
866
+ }
867
+ /**
868
+ The props object given directly to the editor view supports some
869
+ fields that can't be used in plugins:
870
+ */
871
+ interface DirectEditorProps extends EditorProps {
872
+ /**
873
+ The current state of the editor.
874
+ */
875
+ state: EditorState;
876
+ /**
877
+ A set of plugins to use in the view, applying their [plugin
878
+ view](https://prosemirror.net/docs/ref/#state.PluginSpec.view) and
879
+ [props](https://prosemirror.net/docs/ref/#state.PluginSpec.props). Passing plugins with a state
880
+ component (a [state field](https://prosemirror.net/docs/ref/#state.PluginSpec.state) field or a
881
+ [transaction](https://prosemirror.net/docs/ref/#state.PluginSpec.filterTransaction) filter or
882
+ appender) will result in an error, since such plugins must be
883
+ present in the state to work.
884
+ */
885
+ plugins?: readonly Plugin[];
886
+ /**
887
+ The callback over which to send transactions (state updates)
888
+ produced by the view. If you specify this, you probably want to
889
+ make sure this ends up calling the view's
890
+ [`updateState`](https://prosemirror.net/docs/ref/#view.EditorView.updateState) method with a new
891
+ state that has the transaction
892
+ [applied](https://prosemirror.net/docs/ref/#state.EditorState.apply). The callback will be bound to have
893
+ the view instance as its `this` binding.
894
+ */
895
+ dispatchTransaction?: (tr: Transaction) => void;
896
+ }
897
+
898
+ export { DOMEventMap, Decoration, DecorationAttrs, DecorationSet, DecorationSource, DirectEditorProps, EditorProps, EditorView, MarkViewConstructor, NodeView, NodeViewConstructor };
package/dist/index.js CHANGED
@@ -957,19 +957,6 @@ class ViewDesc {
957
957
  let { node, offset } = anchorDOM;
958
958
  if (node.nodeType == 3) {
959
959
  brKludge = !!(offset && node.nodeValue[offset - 1] == "\n");
960
- // Issue #1128
961
- if (brKludge && offset == node.nodeValue.length) {
962
- for (let scan = node, after; scan; scan = scan.parentNode) {
963
- if (after = scan.nextSibling) {
964
- if (after.nodeName == "BR")
965
- anchorDOM = headDOM = { node: after.parentNode, offset: domIndex(after) + 1 };
966
- break;
967
- }
968
- let desc = scan.pmViewDesc;
969
- if (desc && desc.node && desc.node.isBlock)
970
- break;
971
- }
972
- }
973
960
  }
974
961
  else {
975
962
  let prev = node.childNodes[offset - 1];
@@ -2791,10 +2778,12 @@ function closeRight(node, depth) {
2791
2778
  }
2792
2779
  function closeRange(fragment, side, from, to, depth, openEnd) {
2793
2780
  let node = side < 0 ? fragment.firstChild : fragment.lastChild, inner = node.content;
2781
+ if (fragment.childCount > 1)
2782
+ openEnd = 0;
2794
2783
  if (depth < to - 1)
2795
2784
  inner = closeRange(inner, side, from, to, depth + 1, openEnd);
2796
2785
  if (depth >= from)
2797
- inner = side < 0 ? node.contentMatchAt(0).fillBefore(inner, fragment.childCount > 1 || openEnd <= depth).append(inner)
2786
+ inner = side < 0 ? node.contentMatchAt(0).fillBefore(inner, openEnd <= depth).append(inner)
2798
2787
  : inner.append(node.contentMatchAt(node.childCount).fillBefore(Fragment.empty, true));
2799
2788
  return fragment.replaceChild(side < 0 ? 0 : fragment.childCount - 1, node.copy(inner));
2800
2789
  }
@@ -5435,7 +5424,6 @@ function computeDocDeco(view) {
5435
5424
  let attrs = Object.create(null);
5436
5425
  attrs.class = "ProseMirror";
5437
5426
  attrs.contenteditable = String(view.editable);
5438
- attrs.translate = "no";
5439
5427
  view.someProp("attributes", value => {
5440
5428
  if (typeof value == "function")
5441
5429
  value = value(view.state);
@@ -5443,13 +5431,14 @@ function computeDocDeco(view) {
5443
5431
  for (let attr in value) {
5444
5432
  if (attr == "class")
5445
5433
  attrs.class += " " + value[attr];
5446
- if (attr == "style") {
5434
+ else if (attr == "style")
5447
5435
  attrs.style = (attrs.style ? attrs.style + ";" : "") + value[attr];
5448
- }
5449
5436
  else if (!attrs[attr] && attr != "contenteditable" && attr != "nodeName")
5450
5437
  attrs[attr] = String(value[attr]);
5451
5438
  }
5452
5439
  });
5440
+ if (!attrs.translate)
5441
+ attrs.translate = "no";
5453
5442
  return [Decoration.node(0, view.state.doc.content.size, attrs)];
5454
5443
  }
5455
5444
  function updateCursorWrapper(view) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.31.1",
3
+ "version": "1.31.3",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/clipboard.ts CHANGED
@@ -168,9 +168,10 @@ function closeRight(node: Node, depth: number) {
168
168
 
169
169
  function closeRange(fragment: Fragment, side: number, from: number, to: number, depth: number, openEnd: number) {
170
170
  let node = side < 0 ? fragment.firstChild! : fragment.lastChild!, inner = node.content
171
+ if (fragment.childCount > 1) openEnd = 0
171
172
  if (depth < to - 1) inner = closeRange(inner, side, from, to, depth + 1, openEnd)
172
173
  if (depth >= from)
173
- inner = side < 0 ? node.contentMatchAt(0)!.fillBefore(inner, fragment.childCount > 1 || openEnd <= depth)!.append(inner)
174
+ inner = side < 0 ? node.contentMatchAt(0)!.fillBefore(inner, openEnd <= depth)!.append(inner)
174
175
  : inner.append(node.contentMatchAt(node.childCount)!.fillBefore(Fragment.empty, true)!)
175
176
  return fragment.replaceChild(side < 0 ? 0 : fragment.childCount - 1, node.copy(inner))
176
177
  }
package/src/index.ts CHANGED
@@ -478,20 +478,19 @@ function computeDocDeco(view: EditorView) {
478
478
  let attrs = Object.create(null)
479
479
  attrs.class = "ProseMirror"
480
480
  attrs.contenteditable = String(view.editable)
481
- attrs.translate = "no"
482
481
 
483
482
  view.someProp("attributes", value => {
484
483
  if (typeof value == "function") value = value(view.state)
485
484
  if (value) for (let attr in value) {
486
485
  if (attr == "class")
487
486
  attrs.class += " " + value[attr]
488
- if (attr == "style") {
487
+ else if (attr == "style")
489
488
  attrs.style = (attrs.style ? attrs.style + ";" : "") + value[attr]
490
- }
491
489
  else if (!attrs[attr] && attr != "contenteditable" && attr != "nodeName")
492
490
  attrs[attr] = String(value[attr])
493
491
  }
494
492
  })
493
+ if (!attrs.translate) attrs.translate = "no"
495
494
 
496
495
  return [Decoration.node(0, view.state.doc.content.size, attrs)]
497
496
  }
package/src/viewdesc.ts CHANGED
@@ -385,18 +385,6 @@ export class ViewDesc {
385
385
  let {node, offset} = anchorDOM
386
386
  if (node.nodeType == 3) {
387
387
  brKludge = !!(offset && node.nodeValue![offset - 1] == "\n")
388
- // Issue #1128
389
- if (brKludge && offset == node.nodeValue!.length) {
390
- for (let scan: DOMNode | null = node, after; scan; scan = scan.parentNode) {
391
- if (after = scan.nextSibling) {
392
- if (after.nodeName == "BR")
393
- anchorDOM = headDOM = {node: after.parentNode!, offset: domIndex(after) + 1}
394
- break
395
- }
396
- let desc = scan.pmViewDesc
397
- if (desc && desc.node && desc.node.isBlock) break
398
- }
399
- }
400
388
  } else {
401
389
  let prev = node.childNodes[offset - 1]
402
390
  brKludge = prev && (prev.nodeName == "BR" || (prev as HTMLElement).contentEditable == "false")