aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/util/ProsemirrorExampleTransfer.ts71
-rw-r--r--src/client/util/RichTextSchema.tsx71
-rw-r--r--src/client/util/TooltipTextMenu.tsx37
-rw-r--r--src/client/util/prosemirrorPatches.js30
-rw-r--r--src/client/views/OverlayView.tsx2
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx6
-rw-r--r--src/client/views/nodes/FormattedTextBoxComment.tsx4
-rw-r--r--src/client/views/pdf/Page.tsx2
8 files changed, 107 insertions, 116 deletions
diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts
index 5016e72c6..9c4b2d3d1 100644
--- a/src/client/util/ProsemirrorExampleTransfer.ts
+++ b/src/client/util/ProsemirrorExampleTransfer.ts
@@ -2,8 +2,8 @@ import { chainCommands, exitCode, joinDown, joinUp, lift, selectParentNode, setB
import { redo, undo } from "prosemirror-history";
import { undoInputRule } from "prosemirror-inputrules";
import { Schema } from "prosemirror-model";
-import { liftListItem, } from "./prosemirrorPatches.js";
-import { splitListItem, wrapInList, sinkListItem } from "prosemirror-schema-list";
+import { liftListItem, sinkListItem } from "./prosemirrorPatches.js";
+import { splitListItem, wrapInList, } from "prosemirror-schema-list";
import { EditorState, Transaction, TextSelection, NodeSelection } from "prosemirror-state";
import { TooltipTextMenu } from "./TooltipTextMenu";
@@ -62,7 +62,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
return true;
}
return false;
- })
+ });
let cmd = chainCommands(exitCode, (state, dispatch) => {
@@ -93,54 +93,16 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
bind("Mod-s", TooltipTextMenu.insertStar);
- let updateOrderedList = (start: number, rangeStart: any, delta: number, tx2: Transaction, forward: boolean) => {
- let bs = rangeStart.attrs.bulletStyle;
- bs + delta > 0 && tx2.setNodeMarkup(start, rangeStart.type, { mapStyle: rangeStart.attrs.mapStyle, bulletStyle: rangeStart.attrs.bulletStyle + delta }, rangeStart.marks);
-
- let brk = false;
- rangeStart.descendants((node: any, offset: any, index: any) => {
+ let updateBullets = (tx2: Transaction) => {
+ tx2.doc.descendants((node: any, offset: any, index: any) => {
if (node.type === schema.nodes.ordered_list || node.type === schema.nodes.list_item) {
- if (!brk && (bs !== node.attrs.bulletStyle || delta > 0 || (forward && bs > 1))) {
- tx2.setNodeMarkup(start + offset + 1, node.type, { mapStyle: node.attrs.mapStyle, bulletStyle: node.attrs.bulletStyle + delta }, node.marks);
- } else {
- brk = true;
- }
+ let path = (tx2.doc.resolve(offset) as any).path;
+ let depth = Array.from(path).reduce((p: number, c: any) => p + (c.hasOwnProperty("type") && (c as any).type === schema.nodes.ordered_list ? 1 : 0), 0);
+ if (node.type === schema.nodes.ordered_list) depth++;
+ tx2.setNodeMarkup(offset, node.type, { mapStyle: node.attrs.mapStyle, bulletStyle: depth }, node.marks);
}
});
- }
-
- let updateBullets = (tx2: Transaction, refStart: number, delta: number) => {
- let i = refStart;
- for (let i = refStart; i >= 0; i--) {
- let testPos = tx2.doc.nodeAt(i);
- if (!testPos) {
- for (let i = refStart + 1; i <= tx2.doc.nodeSize; i++) {
- try {
- let testPos = tx2.doc.nodeAt(i);
- if (testPos && testPos.type === schema.nodes.ordered_list) {
- updateOrderedList(i, testPos, delta, tx2, true);
- break;
- }
- } catch (e) {
- break;
- }
- }
- break;
- }
- if ((testPos.type === schema.nodes.list_item || testPos.type === schema.nodes.ordered_list)) {
- let start = i;
- let preve = i > 0 && tx2.doc.nodeAt(start - 1);
- if (preve && preve.type === schema.nodes.ordered_list) {
- start = start - 1;
- }
- let rangeStart = tx2.doc.nodeAt(start);
- if (rangeStart) {
- updateOrderedList(start, rangeStart, delta, tx2, false);
- }
- break;
- }
- }
- }
+ };
bind("Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
@@ -148,8 +110,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
var range = ref.$from.blockRange(ref.$to);
var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
if (!sinkListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
- var range = state.selection.$from.blockRange(state.selection.$to);
- updateBullets(tx2, range!.start - 1, 1);
+ updateBullets(tx2);
marks && tx2.ensureMarks([...marks]);
marks && tx2.setStoredMarks([...marks]);
dispatch(tx2);
@@ -157,7 +118,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
let sxf = state.tr.setSelection(TextSelection.create(state.doc, range!.start, range!.end));
let newstate = state.applyTransaction(sxf);
if (!wrapInList(schema.nodes.ordered_list)(newstate.state, (tx2: Transaction) => {
- updateBullets(tx2, range!.start, 1);
+ updateBullets(tx2);
// when promoting to a list, assume list will format things so don't copy the stored marks.
marks && tx2.ensureMarks([...marks]);
marks && tx2.setStoredMarks([...marks]);
@@ -169,14 +130,10 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
});
bind("Shift-Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
- var range = state.selection.$from.blockRange(state.selection.$to);
var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
- let tr = state.tr;
-
- if (!liftListItem(schema.nodes.list_item)(tr, (tx2: Transaction) => {
- var range = tx2.selection.$from.blockRange(tx2.selection.$to);
- updateBullets(tx2, range!.start, -1);
+ if (!liftListItem(schema.nodes.list_item)(state.tr, (tx2: Transaction) => {
+ updateBullets(tx2);
marks && tx2.ensureMarks([...marks]);
marks && tx2.setStoredMarks([...marks]);
dispatch(tx2);
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 75e982872..3174d668c 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -597,8 +597,6 @@ export class ImageResizeView {
}
export class OrderedListView {
- constructor(node: any, view: any, getPos: any) { }
-
update(node: any) {
return false; // if attr's of an ordered_list (e.g., bulletStyle) change, return false forces the dom node to be recreated which is necessary for the bullet labels to update
}
@@ -613,33 +611,33 @@ export class FootnoteView {
constructor(node: any, view: any, getPos: any) {
// We'll need these later
- this.node = node
- this.outerView = view
- this.getPos = getPos
+ this.node = node;
+ this.outerView = view;
+ this.getPos = getPos;
// The node's representation in the editor (empty, for now)
this.dom = document.createElement("footnote");
this.dom.addEventListener("pointerup", this.toggle, true);
// These are used when the footnote is selected
- this.innerView = null
+ this.innerView = null;
}
selectNode() {
const attrs = { ...this.node.attrs };
attrs.visibility = true;
- this.dom.classList.add("ProseMirror-selectednode")
- if (!this.innerView) this.open()
+ this.dom.classList.add("ProseMirror-selectednode");
+ if (!this.innerView) this.open();
}
deselectNode() {
const attrs = { ...this.node.attrs };
attrs.visibility = false;
- this.dom.classList.remove("ProseMirror-selectednode")
- if (this.innerView) this.close()
+ this.dom.classList.remove("ProseMirror-selectednode");
+ if (this.innerView) this.close();
}
open() {
- if (!(this.outerView as any).isOverlay) return;
+ if (!this.outerView.isOverlay) return;
// Append a tooltip to the outer node
- let tooltip = this.dom.appendChild(document.createElement("div"))
+ let tooltip = this.dom.appendChild(document.createElement("div"));
tooltip.className = "footnote-tooltip";
// And put a sub-ProseMirror into that
this.innerView = new EditorView(tooltip, {
@@ -679,56 +677,55 @@ export class FootnoteView {
if (this.innerView) this.close();
else {
this.open();
-
}
}
close() {
- this.innerView && this.innerView.destroy()
- this.innerView = null
- this.dom.textContent = ""
+ this.innerView && this.innerView.destroy();
+ this.innerView = null;
+ this.dom.textContent = "";
}
dispatchInner(tr: any) {
- let { state, transactions } = this.innerView.state.applyTransaction(tr)
- this.innerView.updateState(state)
+ let { state, transactions } = this.innerView.state.applyTransaction(tr);
+ this.innerView.updateState(state);
if (!tr.getMeta("fromOutside")) {
- let outerTr = this.outerView.state.tr, offsetMap = StepMap.offset(this.getPos() + 1)
- for (let i = 0; i < transactions.length; i++) {
- let steps = transactions[i].steps
- for (let j = 0; j < steps.length; j++)
- outerTr.step(steps[j].map(offsetMap))
+ let outerTr = this.outerView.state.tr, offsetMap = StepMap.offset(this.getPos() + 1);
+ for (let steps of transactions) {
+ for (let step of steps) {
+ outerTr.step(step.map(offsetMap));
+ }
}
- if (outerTr.docChanged) this.outerView.dispatch(outerTr)
+ if (outerTr.docChanged) this.outerView.dispatch(outerTr);
}
}
update(node: any) {
- if (!node.sameMarkup(this.node)) return false
- this.node = node
+ if (!node.sameMarkup(this.node)) return false;
+ this.node = node;
if (this.innerView) {
- let state = this.innerView.state
- let start = node.content.findDiffStart(state.doc.content)
- if (start != null) {
- let { a: endA, b: endB } = node.content.findDiffEnd(state.doc.content)
- let overlap = start - Math.min(endA, endB)
- if (overlap > 0) { endA += overlap; endB += overlap }
+ let state = this.innerView.state;
+ let start = node.content.findDiffStart(state.doc.content);
+ if (start !== null) {
+ let { a: endA, b: endB } = node.content.findDiffEnd(state.doc.content);
+ let overlap = start - Math.min(endA, endB);
+ if (overlap > 0) { endA += overlap; endB += overlap; }
this.innerView.dispatch(
state.tr
.replace(start, endB, node.slice(start, endA))
- .setMeta("fromOutside", true))
+ .setMeta("fromOutside", true));
}
}
- return true
+ return true;
}
destroy() {
- if (this.innerView) this.close()
+ if (this.innerView) this.close();
}
stopEvent(event: any) {
- return this.innerView && this.innerView.dom.contains(event.target)
+ return this.innerView && this.innerView.dom.contains(event.target);
}
- ignoreMutation() { return true }
+ ignoreMutation() { return true; }
}
export class SummarizedView {
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index ce7b04e31..6d375fc1d 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -4,7 +4,7 @@ import { action, observable } from "mobx";
import { Dropdown, icons, MenuItem } from "prosemirror-menu"; //no import css
import { Mark, MarkType, Node as ProsNode, NodeType, ResolvedPos, Schema } from "prosemirror-model";
import { wrapInList } from 'prosemirror-schema-list';
-import { EditorState, NodeSelection, TextSelection } from "prosemirror-state";
+import { EditorState, NodeSelection, TextSelection, Transaction } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import { Doc, Field, Opt } from "../../new_fields/Doc";
import { Id } from "../../new_fields/FieldSymbols";
@@ -509,30 +509,37 @@ export class TooltipTextMenu {
}
}
+ updateBullets = (tx2: Transaction, style: string) => {
+ tx2.doc.descendants((node: any, offset: any, index: any) => {
+ if (node.type === schema.nodes.ordered_list || node.type === schema.nodes.list_item) {
+ let path = (tx2.doc.resolve(offset) as any).path;
+ let depth = Array.from(path).reduce((p: number, c: any) => p + (c.hasOwnProperty("type") && (c as any).type === schema.nodes.ordered_list ? 1 : 0), 0);
+ if (node.type === schema.nodes.ordered_list) depth++;
+ tx2.setNodeMarkup(offset, node.type, { mapStyle: style, bulletStyle: depth }, node.marks);
+ }
+ });
+ };
//remove all node typeand apply the passed-in one to the selected text
- changeToNodeType(nodeType: NodeType | undefined, view: EditorView) {
+ changeToNodeType = (nodeType: NodeType | undefined, view: EditorView) => {
//remove oldif (nodeType) { //add new
if (nodeType === schema.nodes.bullet_list) {
wrapInList(nodeType)(view.state, view.dispatch);
} else {
- var ref = view.state.selection;
- var range = ref.$from.blockRange(ref.$to);
var marks = view.state.storedMarks || (view.state.selection.$to.parentOffset && view.state.selection.$from.marks());
- wrapInList(schema.nodes.ordered_list)(view.state, (tx2: any) => {
- const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
- let path = resolvedPos.path;
- for (let i = path.length - 1; i > 0; i--) {
- if (path[i].type === schema.nodes.ordered_list) {
- path[i].attrs.bulletStyle = 1;
- path[i].attrs.mapStyle = (nodeType as any).attrs.mapStyle;
- break;
- }
- }
+ if (!wrapInList(schema.nodes.ordered_list)(view.state, (tx2: any) => {
+ this.updateBullets(tx2, (nodeType as any).attrs.mapStyle);
marks && tx2.ensureMarks([...marks]);
marks && tx2.setStoredMarks([...marks]);
view.dispatch(tx2);
- });
+ })) {
+ let tx2 = view.state.tr;
+ this.updateBullets(tx2, (nodeType as any).attrs.mapStyle);
+ marks && tx2.ensureMarks([...marks]);
+ marks && tx2.setStoredMarks([...marks]);
+
+ view.dispatch(tx2);
+ }
}
}
diff --git a/src/client/util/prosemirrorPatches.js b/src/client/util/prosemirrorPatches.js
index c273c2323..6bf4395ad 100644
--- a/src/client/util/prosemirrorPatches.js
+++ b/src/client/util/prosemirrorPatches.js
@@ -6,6 +6,7 @@ var prosemirrorTransform = require('prosemirror-transform');
var prosemirrorModel = require('prosemirror-model');
exports.liftListItem = liftListItem;
+exports.sinkListItem = sinkListItem;
// :: (NodeType) → (state: EditorState, dispatch: ?(tr: Transaction)) → bool
// Create a command to lift the list item around the selection up into
// a wrapping list.
@@ -59,4 +60,33 @@ function liftOutOfList(tr, dispatch, range) {
atStart ? 0 : 1, atEnd ? 0 : 1), atStart ? 0 : 1));
dispatch(tr.scrollIntoView());
return true
+}
+
+// :: (NodeType) → (state: EditorState, dispatch: ?(tr: Transaction)) → bool
+// Create a command to sink the list item around the selection down
+// into an inner list.
+function sinkListItem(itemType) {
+ return function (state, dispatch) {
+ var ref = state.selection;
+ var $from = ref.$from;
+ var $to = ref.$to;
+ var range = $from.blockRange($to, function (node) { return node.childCount && node.firstChild.type == itemType; });
+ if (!range) { return false }
+ var startIndex = range.startIndex;
+ if (startIndex == 0) { return false }
+ var parent = range.parent, nodeBefore = parent.child(startIndex - 1);
+ if (nodeBefore.type != itemType) { return false; }
+
+ if (dispatch) {
+ var nestedBefore = nodeBefore.lastChild && nodeBefore.lastChild.type == parent.type;
+ var inner = prosemirrorModel.Fragment.from(nestedBefore ? itemType.create() : null);
+ let slice = new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(itemType.create(null, prosemirrorModel.Fragment.from(parent.type.create(parent.attrs, inner)))),
+ nestedBefore ? 3 : 1, 0);
+ var before = range.start, after = range.end;
+ dispatch(state.tr.step(new prosemirrorTransform.ReplaceAroundStep(before - (nestedBefore ? 3 : 1), after,
+ before, after, slice, 1, true))
+ .scrollIntoView());
+ }
+ return true
+ }
} \ No newline at end of file
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 54ab8696e..fe06e4440 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -191,7 +191,7 @@ export class OverlayView extends React.Component {
zoomToScale={emptyFunction}
getScale={returnOne} />
</div>;
- })
+ });
}
render() {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 4cb52ec78..f9ad040a2 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -174,7 +174,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
syncNodeSelection(view: any, sel: any) {
if (sel instanceof NodeSelection) {
var desc = view.docView.descAt(sel.from);
- if (desc != view.lastSelectedViewDesc) {
+ if (desc !== view.lastSelectedViewDesc) {
if (view.lastSelectedViewDesc) {
view.lastSelectedViewDesc.deselectNode();
view.lastSelectedViewDesc = null;
@@ -635,8 +635,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
nodeViews: {
image(node, view, getPos) { return new ImageResizeView(node, view, getPos); },
star(node, view, getPos) { return new SummarizedView(node, view, getPos); },
- ordered_list(node, view, getPos) { return new OrderedListView(node, view, getPos); },
- footnote(node, view, getPos) { return new FootnoteView(node, view, getPos) }
+ ordered_list(node, view, getPos) { return new OrderedListView(); },
+ footnote(node, view, getPos) { return new FootnoteView(node, view, getPos); }
},
clipboardTextSerializer: this.clipboardTextSerializer,
handlePaste: this.handlePaste,
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index 255000936..2d2fff06d 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -92,7 +92,7 @@ export class FormattedTextBoxComment {
if (lastState && lastState.doc.eq(state.doc) &&
lastState.selection.eq(state.selection)) return;
- let set = "none"
+ let set = "none";
if (state.selection.$from) {
let nbef = findStartOfMark(state.selection.$from, view, findOtherUserMark);
let naft = findEndOfMark(state.selection.$from, view, findOtherUserMark);
@@ -130,7 +130,7 @@ export class FormattedTextBoxComment {
if (mark.attrs.href.indexOf(Utils.prepend("/doc/")) === 0) {
let docTarget = mark.attrs.href.replace(Utils.prepend("/doc/"), "").split("?")[0];
docTarget && DocServer.GetRefField(docTarget).then(linkDoc =>
- (linkDoc as Doc) && (FormattedTextBoxComment.tooltipText.textContent = "link :" + StrCast((linkDoc as Doc)!.title)));
+ (linkDoc as Doc) && (FormattedTextBoxComment.tooltipText.textContent = "link :" + StrCast((linkDoc as Doc).title)));
}
// These are in screen coordinates
// let start = view.coordsAtPos(state.selection.from), end = view.coordsAtPos(state.selection.to);
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 8df2dce29..856e883e7 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -64,7 +64,7 @@ export default class Page extends React.Component<IPageProps> {
// lower scale = easier to read at small sizes, higher scale = easier to read at large sizes
if (this._state !== "rendering" && !this._page && this._canvas.current && this._textLayer.current) {
this._state = "rendering";
- let viewport = page.getViewport({ scale: scale });
+ let viewport = page.getViewport(scale);
this._canvas.current.width = this._width = viewport.width;
this._canvas.current.height = this._height = viewport.height;
this.props.pageLoaded(viewport);