From 47ecf8d30f4aa5e25a659fc7f3c0c1487420150e Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 9 May 2019 20:59:10 -0400 Subject: merge with master, but haven't reconciled internal and external linking --- src/client/util/RichTextSchema.tsx | 87 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 9ef71e305..c0e6f7899 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -84,6 +84,7 @@ export const nodes: { [index: string]: NodeSpec } = { inline: true, attrs: { src: {}, + width: { default: "100px" }, alt: { default: null }, title: { default: null } }, @@ -94,11 +95,16 @@ export const nodes: { [index: string]: NodeSpec } = { return { src: dom.getAttribute("src"), title: dom.getAttribute("title"), - alt: dom.getAttribute("alt") - }; + alt: dom.getAttribute("alt"), + width: Math.min(100, Number(dom.getAttribute("width"))), + } } }], - toDOM(node: any) { return ["img", node.attrs]; } + // TODO if we don't define toDom, something weird happens: dragging the image will not move it but clone it. Why? + toDOM(node) { + const attrs = { style: `width: ${node.attrs.width}` } + return ["img", { ...node.attrs, ...attrs }] + } }, // :: NodeSpec A hard line break, represented in the DOM as `
`. @@ -290,6 +296,13 @@ export const marks: { [index: string]: MarkSpec } = { }] }, + p14: { + parseDOM: [{ style: 'font-size: 14px;' }], + toDOM: () => ['span', { + style: 'font-size: 14px;' + }] + }, + p16: { parseDOM: [{ style: 'font-size: 16px;' }], toDOM: () => ['span', { @@ -325,7 +338,75 @@ export const marks: { [index: string]: MarkSpec } = { }] }, }; +function getFontSize(element: any) { + return parseFloat((getComputedStyle(element) as any).fontSize); +} + +export class ImageResizeView { + _handle: HTMLElement; + _img: HTMLElement; + _outer: HTMLElement; + constructor(node: any, view: any, getPos: any) { + this._handle = document.createElement("span"); + this._img = document.createElement("img"); + this._outer = document.createElement("span"); + this._outer.style.position = "relative"; + this._outer.style.width = node.attrs.width; + this._outer.style.display = "inline-block"; + this._outer.style.overflow = "hidden"; + + this._img.setAttribute("src", node.attrs.src); + this._img.style.width = "100%"; + this._handle.style.position = "absolute"; + this._handle.style.width = "20px"; + this._handle.style.height = "20px"; + this._handle.style.backgroundColor = "blue"; + this._handle.style.borderRadius = "15px"; + this._handle.style.display = "none"; + this._handle.style.bottom = "-10px"; + this._handle.style.right = "-10px"; + let self = this; + this._handle.onpointerdown = function (e: any) { + e.preventDefault(); + e.stopPropagation(); + const startX = e.pageX; + const startWidth = parseFloat(node.attrs.width); + const onpointermove = (e: any) => { + const currentX = e.pageX; + const diffInPx = currentX - startX; + self._outer.style.width = `${startWidth + diffInPx}`; + } + + const onpointerup = () => { + document.removeEventListener("pointermove", onpointermove); + document.removeEventListener("pointerup", onpointerup); + view.dispatch( + view.state.tr.setNodeMarkup(getPos(), null, + { src: node.attrs.src, width: self._outer.style.width }) + .setSelection(view.state.selection)); + } + + document.addEventListener("pointermove", onpointermove) + document.addEventListener("pointerup", onpointerup) + } + this._outer.appendChild(this._handle); + this._outer.appendChild(this._img); + (this as any).dom = this._outer; + } + + selectNode() { + this._img.classList.add("ProseMirror-selectednode"); + + this._handle.style.display = ""; + } + + deselectNode() { + this._img.classList.remove("ProseMirror-selectednode"); + + this._handle.style.display = "none"; + } +} // :: Schema // This schema rougly corresponds to the document schema used by // [CommonMark](http://commonmark.org/), minus the list elements, -- cgit v1.2.3-70-g09d2 From 3451ce40cbd488cede7d29b6e39594f740e366b5 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 11 May 2019 19:15:17 -0400 Subject: basic internal drag and drop of images via embedded link --- src/client/util/DragManager.ts | 15 +++++++++ src/client/util/RichTextSchema.tsx | 26 +++++++++++++++ src/client/views/DocumentDecorations.tsx | 50 +++++++++++++++++++++++++++++ src/client/views/nodes/DocumentView.tsx | 1 + src/client/views/nodes/FormattedTextBox.tsx | 8 +++++ 5 files changed, 100 insertions(+) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 266679c16..759698abc 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -4,6 +4,7 @@ import { Cast } from "../../new_fields/Types"; import { emptyFunction } from "../../Utils"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import * as globalCssVariables from "../views/globalCssVariables.scss"; +import { URLField } from "../../new_fields/URLField"; export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag(_reference: React.RefObject, docFunc: () => Doc, moveFunc?: DragManager.MoveFunction, dropAction?: dropActionType) { @@ -177,10 +178,24 @@ export namespace DragManager { [id: string]: any; } + export class EmbedDragData { + constructor(embeddableSourceDoc: Doc) { + this.embeddableSourceDoc = embeddableSourceDoc; + this.urlField = Cast(embeddableSourceDoc.data, URLField)!; + } + embeddableSourceDoc: Doc; + urlField: URLField; + [id: string]: any; + } + export function StartLinkDrag(ele: HTMLElement, dragData: LinkDragData, downX: number, downY: number, options?: DragOptions) { StartDrag([ele], dragData, downX, downY, options); } + export function StartEmbedDrag(ele: HTMLElement, dragData: EmbedDragData, downX: number, downY: number, options?: DragOptions) { + StartDrag([ele], dragData, downX, downY, options); + } + export let AbortDrag: () => void = emptyFunction; function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: { [id: string]: any }) => void) { diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index c0e6f7899..742ac5434 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -107,6 +107,32 @@ export const nodes: { [index: string]: NodeSpec } = { } }, + video: { + inline: true, + attrs: { + src: {}, + width: { default: "100px" }, + alt: { default: null }, + title: { default: null } + }, + group: "inline", + draggable: true, + parseDOM: [{ + tag: "video[src]", getAttrs(dom: any) { + return { + src: dom.getAttribute("src"), + title: dom.getAttribute("title"), + alt: dom.getAttribute("alt"), + width: Math.min(100, Number(dom.getAttribute("width"))), + } + } + }], + toDOM(node) { + const attrs = { style: `width: ${node.attrs.width}` } + return ["video", { ...node.attrs, ...attrs }] + } + }, + // :: NodeSpec A hard line break, represented in the DOM as `
`. hard_break: { inline: true, diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 4786b4de6..1a79c4192 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -28,6 +28,7 @@ import { CollectionView } from "./collections/CollectionView"; import { DocumentManager } from "../util/DocumentManager"; import { FormattedTextBox } from "./nodes/FormattedTextBox"; import { FieldView } from "./nodes/FieldView"; +import { URLField } from "../../new_fields/URLField"; library.add(faLink); @@ -42,6 +43,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> private _titleHeight = 20; private _linkButton = React.createRef(); private _linkerButton = React.createRef(); + private _embedButton = React.createRef(); private _downX = 0; private _downY = 0; private _iconDoc?: Doc = undefined; @@ -328,12 +330,27 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> document.removeEventListener("pointerup", this.onLinkerButtonUp); document.addEventListener("pointerup", this.onLinkerButtonUp); } + + onEmbedButtonDown = (e: React.PointerEvent): void => { + e.stopPropagation(); + document.removeEventListener("pointermove", this.onEmbedButtonMoved); + document.addEventListener("pointermove", this.onEmbedButtonMoved); + document.removeEventListener("pointerup", this.onEmbedButtonUp); + document.addEventListener("pointerup", this.onEmbedButtonUp); + } + onLinkerButtonUp = (e: PointerEvent): void => { document.removeEventListener("pointermove", this.onLinkerButtonMoved); document.removeEventListener("pointerup", this.onLinkerButtonUp); e.stopPropagation(); } + onEmbedButtonUp = (e: PointerEvent): void => { + document.removeEventListener("pointermove", this.onEmbedButtonMoved); + document.removeEventListener("pointerup", this.onEmbedButtonUp); + e.stopPropagation(); + } + @action onLinkerButtonMoved = (e: PointerEvent): void => { if (this._linkerButton.current !== null) { @@ -353,6 +370,25 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> e.stopPropagation(); } + @action + onEmbedButtonMoved = (e: PointerEvent): void => { + if (this._embedButton.current !== null) { + document.removeEventListener("pointermove", this.onEmbedButtonMoved); + document.removeEventListener("pointerup", this.onEmbedButtonUp); + + let dragDocView = SelectionManager.SelectedDocuments()[0]; + let dragData = new DragManager.EmbedDragData(dragDocView.props.Document); + + DragManager.StartEmbedDrag(dragDocView.ContentDiv!, dragData, e.x, e.y, { + handlers: { + dragComplete: action(emptyFunction), + }, + hideSource: false + }); + } + e.stopPropagation(); + } + onLinkButtonDown = (e: React.PointerEvent): void => { e.stopPropagation(); document.removeEventListener("pointermove", this.onLinkButtonMoved); @@ -495,6 +531,19 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> // e.stopPropagation(); // } + considerEmbed = () => { + let thisDoc = SelectionManager.SelectedDocuments()[0].props.Document; + let canEmbed = thisDoc.data && Cast(thisDoc.data, URLField); + if (!canEmbed) return (null); + return ( +
+
+ +
+
+ ); + } + render() { var bounds = this.Bounds; let seldoc = SelectionManager.SelectedDocuments().length ? SelectionManager.SelectedDocuments()[0] : undefined; @@ -589,6 +638,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> + {this.considerEmbed()} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5aa74c703..63149187b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -26,6 +26,7 @@ import { CurrentUserUtils } from "../../../server/authentication/models/current_ import { DocServer } from "../../DocServer"; import { Id } from "../../../new_fields/RefField"; import { PresentationView } from "../PresentationView"; +import { DatamartAugmentParameters } from "../../northstar/model/idea/idea"; const linkSchema = createSchema({ title: "string", diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index df3eb159b..791794beb 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -26,6 +26,8 @@ import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import React = require("react"); +import { View } from "@react-pdf/renderer"; +import { NodeType } from "prosemirror-model"; // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // @@ -107,6 +109,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { + // We're dealing with a link to a document if (de.data instanceof DragManager.LinkDragData) { let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.Document; @@ -116,6 +119,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe Doc.MakeLink(protoSrc ? protoSrc : sourceDoc, protoDest ? protoDest : destDoc); de.data.droppedDocuments.push(destDoc); e.stopPropagation(); + } else if (de.data instanceof DragManager.EmbedDragData) { + // We're dealing with an internal document drop + let url = de.data.urlField.url.href; + let model: NodeType = (url.includes(".mov") || url.includes(".mp4")) ? schema.nodes.video : schema.nodes.image; + this._editorView!.dispatch(this._editorView!.state.tr.insert(0, model.create({ src: url }))); } } -- cgit v1.2.3-70-g09d2 From 08134c962bab2cd62507415f1a67cd921069d8e3 Mon Sep 17 00:00:00 2001 From: ab Date: Fri, 7 Jun 2019 15:00:36 -0400 Subject: fixed marquee --- src/client/util/ProsemirrorKeymap.ts | 19 ++++++++++++- src/client/util/RichTextSchema.tsx | 17 ++++++++++++ src/client/util/TooltipTextMenu.scss | 6 +++-- src/client/util/TooltipTextMenu.tsx | 31 +++++++++++++++++++++- src/client/views/MainOverlayTextBox.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 9 ++++--- 6 files changed, 76 insertions(+), 8 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/ProsemirrorKeymap.ts b/src/client/util/ProsemirrorKeymap.ts index 71644cd88..89d01486e 100644 --- a/src/client/util/ProsemirrorKeymap.ts +++ b/src/client/util/ProsemirrorKeymap.ts @@ -1,4 +1,4 @@ -import { Schema } from "prosemirror-model"; +import { Schema, NodeType } from "prosemirror-model"; import { wrapIn, setBlockType, chainCommands, toggleMark, exitCode, joinUp, joinDown, lift, selectParentNode @@ -24,6 +24,22 @@ export default function buildKeymap>(schema: S, mapKeys?: keys[key] = cmd; } + function insertStar(state: EditorState, dispatch: ((tr: Transaction) => void)) { + console.log("creating star..."); + let type = schema.nodes.star as NodeType; + let { $from } = state.selection; + if (!$from.parent.canReplaceWith($from.index(), $from.index(), type)) { + return false; + } + if (dispatch) { + dispatch(state.tr.replaceSelectionWith(type.create())); + } + return true; + } + + console.log("star? hullo"); + bind("Mod-space", insertStar); + bind("Mod-z", undo); bind("Shift-Mod-z", redo); bind("Backspace", undoInputRule); @@ -79,6 +95,7 @@ export default function buildKeymap>(schema: S, mapKeys?: } if (type = schema.nodes.paragraph) { bind("Shift-Ctrl-0", setBlockType(type)); + bind("Mod-space", insertStar); } if (type = schema.nodes.code_block) { bind("Shift-Ctrl-\\", setBlockType(type)); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 3e3e98206..8fae821a5 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -26,6 +26,13 @@ export const nodes: { [index: string]: NodeSpec } = { toDOM() { return pDOM; } }, + star: { + inline: true, + group: "inline", + toDOM() { return ["star", "🟊"]; }, + parseDOM: [{ tag: "star" }] + }, + // :: NodeSpec A blockquote (`
`) wrapping one or more blocks. blockquote: { content: "block+", @@ -222,6 +229,15 @@ export const marks: { [index: string]: MarkSpec } = { toDOM: () => ['sup'] }, + collapse: { + parseDOM: [{ style: 'color: blue' }], + toDOM() { + return ['span', { + style: 'color: blue' + }] + } + }, + // :: MarkSpec Code font mark. Represented as a `` element. code: { @@ -280,6 +296,7 @@ export const marks: { [index: string]: MarkSpec } = { }] }, + /** FONT SIZES */ p10: { diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index e2862f093..0720a73a3 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -133,7 +133,7 @@ position: relative; min-height: 1em; color: white; - padding: 1px 6px; + padding: 10px 10px; top: 0; left: 0; right: 0; border-bottom: 1px solid silver; background:$dark-color; @@ -239,10 +239,12 @@ border: 1px solid silver; border-radius: 15px; padding: 2px 10px; - margin-bottom: 15px; + margin-bottom: 60px; -webkit-transform: translateX(-50%); transform: translateX(-50%); pointer-events: all; + height: 100px; + width:500px; .ProseMirror-example-setup-style hr { padding: 2px 10px; border: none; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 7c5437510..1f1ad9cd4 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -22,12 +22,12 @@ import { throwStatement } from "babel-types"; import { View } from "@react-pdf/renderer"; import { DragManager } from "./DragManager"; import { Doc, Opt, Field } from "../../new_fields/Doc"; -import { Utils } from "../northstar/utils/Utils"; import { DocServer } from "../DocServer"; import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import { DocumentManager } from "./DocumentManager"; import { Id } from "../../new_fields/FieldSymbols"; +import { Utils } from "../../Utils"; const SVG = "http://www.w3.org/2000/svg"; @@ -74,6 +74,7 @@ export class TooltipTextMenu { { command: toggleMark(schema.marks.strikethrough), dom: this.icon("S", "strikethrough", "Strikethrough") }, { command: toggleMark(schema.marks.superscript), dom: this.icon("s", "superscript", "Superscript") }, { command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript", "Subscript") }, + { command: toggleMark(schema.marks.collapse), dom: this.icon("C", 'collapse', 'Collapse') } // { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, // { command: wrapInList(schema.nodes.ordered_list), dom: this.icon("1)", "bullets") }, // { command: lift, dom: this.icon("<", "lift") }, @@ -231,6 +232,15 @@ export class TooltipTextMenu { this.linkEditor.appendChild(this.linkText); this.linkEditor.appendChild(linkBtn); this.tooltip.appendChild(this.linkEditor); + + let starButton = document.createElement("button"); + starButton.textContent = "ST"; + starButton.onclick = () => { + let state = this.view.state; + this.insertStar(state, this.view.dispatch); + } + + this.tooltip.appendChild(starButton); } let node = this.view.state.selection.$from.nodeAfter; @@ -256,6 +266,19 @@ export class TooltipTextMenu { link = node && node.marks.find(m => m.type.name === "link"); } + insertStar(state: any, dispatch: any) { + console.log("creating star..."); + let type = schema.nodes.star; + let { $from } = state.selection; + if (!$from.parent.canReplaceWith($from.index(), $from.index(), type)) { + return false; + } + if (dispatch) { + dispatch(state.tr.replaceSelectionWith(type.create())); + } + return true; + } + //will display a remove-list-type button if selection is in list, otherwise will show list type dropdown updateListItemDropdown(label: string, listTypeBtn: Node) { //remove old btn @@ -426,6 +449,12 @@ export class TooltipTextMenu { this.tooltip.style.width = 225 + "px"; this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px"; + this.tooltip.style.top = "-100px"; + //this.tooltip.style.height = "100px"; + + // let transform = this.editorProps.ScreenToLocalTransform(); + // this.tooltip.style.width = `${225 / transform.Scale}px`; + // Utils //UPDATE LIST ITEM DROPDOWN this.listTypeBtnDom = this.updateListItemDropdown(":", this.listTypeBtnDom!); diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 24327b995..d1224febe 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -102,6 +102,6 @@ export class MainOverlayTextBox extends React.Component ; } - else return (null); Z + else return (null); } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 9ec941eff..563fbb186 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -45,12 +45,14 @@ export class MarqueeView extends React.Component _commandExecuted = false; @action - cleanupInteractions = (all: boolean = false) => { + cleanupInteractions = (all: boolean = false, rem_keydown: boolean = true) => { if (all) { document.removeEventListener("pointerup", this.onPointerUp, true); document.removeEventListener("pointermove", this.onPointerMove, true); } - document.removeEventListener("keydown", this.marqueeCommand, true); + if (rem_keydown) { + document.removeEventListener("keydown", this.marqueeCommand, true); + } this._visible = false; } @@ -180,6 +182,7 @@ export class MarqueeView extends React.Component @action onPointerUp = (e: PointerEvent): void => { + console.log("pointer up!"); if (this._visible) { let mselect = this.marqueeSelect(); if (!e.shiftKey) { @@ -187,7 +190,7 @@ export class MarqueeView extends React.Component } this.props.selectDocuments(mselect.length ? mselect : [this.props.container.props.Document]); } - this.cleanupInteractions(true); + this.cleanupInteractions(true, false); if (e.altKey) { e.preventDefault(); } -- cgit v1.2.3-70-g09d2 From bf73b629c78d0db0b8d4bcf6aadd6609b3fe1689 Mon Sep 17 00:00:00 2001 From: ab Date: Tue, 11 Jun 2019 12:02:00 -0400 Subject: star node, trying to set selection as its attribute for copy/paste like behavior --- src/client/util/RichTextSchema.tsx | 13 +++++++++++++ src/client/util/TooltipTextMenu.tsx | 23 ++++++++++++----------- src/client/views/nodes/FormattedTextBox.tsx | 6 ++++-- 3 files changed, 29 insertions(+), 13 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 8fae821a5..a29036f19 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -28,6 +28,7 @@ export const nodes: { [index: string]: NodeSpec } = { star: { inline: true, + attrs: { oldtext: { default: "suhhhh" } }, group: "inline", toDOM() { return ["star", "🟊"]; }, parseDOM: [{ tag: "star" }] @@ -424,6 +425,18 @@ export class ImageResizeView { this._handle.style.display = "none"; } } + +export class SummarizedView { + _collapsed: HTMLElement; + _selection: any; + constructor(node: any) { + this._collapsed = document.createElement("star"); + this._collapsed.onpointerdown = function (e: any) { + console.log("star pressed!"); + }; + + } +} // :: Schema // This schema rougly corresponds to the document schema used by // [CommonMark](http://commonmark.org/), minus the list elements, diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 366105ad9..c5d016547 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -1,6 +1,6 @@ import { action, IReactionDisposer, reaction } from "mobx"; import { Dropdown, DropdownSubmenu, MenuItem, MenuItemSpec, renderGrouped, icons, } from "prosemirror-menu"; //no import css -import { baseKeymap, lift } from "prosemirror-commands"; +import { baseKeymap, lift, deleteSelection } from "prosemirror-commands"; import { history, redo, undo } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; import { EditorState, Transaction, NodeSelection, TextSelection } from "prosemirror-state"; @@ -28,6 +28,7 @@ import { CollectionDockingView } from "../views/collections/CollectionDockingVie import { DocumentManager } from "./DocumentManager"; import { Id } from "../../new_fields/FieldSymbols"; import { Utils } from "../../Utils"; +// import { wrap } from "module"; const SVG = "http://www.w3.org/2000/svg"; @@ -74,7 +75,7 @@ export class TooltipTextMenu { { command: toggleMark(schema.marks.strikethrough), dom: this.icon("S", "strikethrough", "Strikethrough") }, { command: toggleMark(schema.marks.superscript), dom: this.icon("s", "superscript", "Superscript") }, { command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript", "Subscript") }, - { command: toggleMark(schema.marks.collapse), dom: this.icon("C", 'collapse', 'Collapse') } + { command: deleteSelection, dom: this.icon("C", 'collapse', 'Collapse') } // { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, // { command: wrapInList(schema.nodes.ordered_list), dom: this.icon("1)", "bullets") }, // { command: lift, dom: this.icon("<", "lift") }, @@ -274,18 +275,18 @@ export class TooltipTextMenu { insertStar(state: EditorState, dispatch: any) { console.log("creating star..."); let type = schema.nodes.star; - //let {$from} = state.selection; let select = state.selection; + let node = select.$from.nodeAfter; + if (node) { + console.log("node"); + console.log(node.type.name); + if (node.type.name === "star") { + console.log(node.attrs.oldtext); + } + } if (dispatch) { - dispatch(state.tr.setMeta('select.visible', false)); + dispatch(state.tr.replaceSelectionWith(type.create({ attrs: { oldtext: select } }))); } - // console.log($from); - // if (!$from.parent.canReplaceWith($from.index(), $from.index(), type)) { - // return false; - // } - // if (dispatch) { - // dispatch(state.tr.replaceSelectionWith(type.create())); - // } return true; } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 5c635cc0c..b40c6d580 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -16,7 +16,7 @@ import { DocumentManager } from "../../util/DocumentManager"; import { DragManager } from "../../util/DragManager"; import buildKeymap from "../../util/ProsemirrorKeymap"; import { inpRules } from "../../util/RichTextRules"; -import { ImageResizeView, schema } from "../../util/RichTextSchema"; +import { SummarizedView, ImageResizeView, schema } from "../../util/RichTextSchema"; import { SelectionManager } from "../../util/SelectionManager"; import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; import { TooltipTextMenu } from "../../util/TooltipTextMenu"; @@ -29,6 +29,7 @@ import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import React = require("react"); import { DocUtils } from '../../documents/Documents'; +import { start } from 'repl'; library.add(faEdit); library.add(faSmile); @@ -189,7 +190,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config), dispatchTransaction: this.dispatchTransaction, nodeViews: { - image(node, view, getPos) { return new ImageResizeView(node, view, getPos); } + image(node, view, getPos) { return new ImageResizeView(node, view, getPos); }, + //star(node, view, getPos) { return new SummarizedView(node); } } }); let text = StrCast(this.props.Document.documentText); -- cgit v1.2.3-70-g09d2 From a7cb61db19c3e34dcf3c91152c04d4aea2980682 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 12 Jun 2019 03:00:59 -0400 Subject: prototyep working version of elision -- however, it doesn't work once the text box is deselected/reloaded. didn't look into why --- src/client/util/RichTextSchema.tsx | 64 +++++++++++++++++++++++------ src/client/util/TooltipTextMenu.tsx | 18 ++------ src/client/views/nodes/FormattedTextBox.tsx | 2 +- 3 files changed, 57 insertions(+), 27 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index a29036f19..84c2fd5c3 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -1,9 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType } from "prosemirror-model"; -import { joinUp, lift, setBlockType, toggleMark, wrapIn } from 'prosemirror-commands'; +import { joinUp, lift, setBlockType, toggleMark, wrapIn, selectNodeForward, deleteSelection } from 'prosemirror-commands'; import { redo, undo } from 'prosemirror-history'; import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list'; -import { EditorState, Transaction, NodeSelection, } from "prosemirror-state"; +import { EditorState, Transaction, NodeSelection, TextSelection, Selection, } from "prosemirror-state"; import { EditorView, } from "prosemirror-view"; const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], @@ -26,13 +26,6 @@ export const nodes: { [index: string]: NodeSpec } = { toDOM() { return pDOM; } }, - star: { - inline: true, - attrs: { oldtext: { default: "suhhhh" } }, - group: "inline", - toDOM() { return ["star", "🟊"]; }, - parseDOM: [{ tag: "star" }] - }, // :: NodeSpec A blockquote (`
`) wrapping one or more blocks. blockquote: { @@ -85,6 +78,29 @@ export const nodes: { [index: string]: NodeSpec } = { group: "inline" }, + star: { + inline: true, + attrs: { + visibility: { default: false }, + oldtext: { default: undefined }, + oldtextlen: { default: 0 } + + }, + group: "inline", + toDOM(node) { + const attrs = { style: `width: 40px` }; + return ["span", { ...node.attrs, ...attrs }]; + }, + parseDOM: [{ + tag: "span", getAttrs(dom: any) { + return { + visibility: dom.getAttribute("visibility"), + oldtext: dom.getAttribute("oldtext"), + oldtextlen: dom.getAttribute("oldtextlen"), + } + } + }] + }, // :: NodeSpec An inline image (``) node. Supports `src`, // `alt`, and `href` attributes. The latter two default to the empty // string. @@ -428,13 +444,37 @@ export class ImageResizeView { export class SummarizedView { _collapsed: HTMLElement; - _selection: any; - constructor(node: any) { - this._collapsed = document.createElement("star"); + constructor(node: any, view: any, getPos: any) { + this._collapsed = document.createElement("span"); + this._collapsed.textContent = "..."; + this._collapsed.style.opacity = "0.5"; + this._collapsed.style.background = "yellow"; + this._collapsed.style.position = "relative"; + this._collapsed.style.width = "40px"; + this._collapsed.style.height = "20px"; this._collapsed.onpointerdown = function (e: any) { console.log("star pressed!"); + if (node.attrs.visibility) { + let y = getPos(); + view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, y + 1, y + 1 + node.attrs.oldtextlen))); + view.dispatch(view.state.tr.deleteSelection(view.state, () => { })); + + } else { + let y = getPos(); + view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, y + 1, y + 1))); + view.dispatch(view.state.tr.replaceSelection(node.attrs.oldtext)); + } + node.attrs.visibility = !node.attrs.visibility; + e.preventDefault(); + e.stopPropagation(); }; + (this as any).dom = this._collapsed; + + } + selectNode() { + } + deselectNode() { } } // :: Schema diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 905f1969c..6cc71be39 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -274,21 +274,11 @@ export class TooltipTextMenu { insertStar(state: EditorState, dispatch: any) { console.log("creating star..."); - let type = schema.nodes.star; - let select = state.selection; - let node = select.$from.nodeAfter; - if (node) { - if (node.type.name === "star") { - let oldselection = node.attrs.oldtext; - if (dispatch) { - dispatch(state.tr.replaceSelection(oldselection.content())); - } - return true; - } - } + let newNode = schema.nodes.star.create(); if (dispatch) { - let newNode = type.create(); - newNode.attrs.oldtext = select; + newNode.attrs.visibility = false; + newNode.attrs.oldtext = state.selection.content(); + newNode.attrs.oldtextlen = state.selection.to - state.selection.from; dispatch(state.tr.replaceSelectionWith(newNode)); } return true; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index b40c6d580..3ba108a57 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -191,7 +191,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe dispatchTransaction: this.dispatchTransaction, nodeViews: { image(node, view, getPos) { return new ImageResizeView(node, view, getPos); }, - //star(node, view, getPos) { return new SummarizedView(node); } + star(node, view, getPos) { return new SummarizedView(node, view, getPos); } } }); let text = StrCast(this.props.Document.documentText); -- cgit v1.2.3-70-g09d2 From 258be09fcfa48f355751cbe99291892018a91ffc Mon Sep 17 00:00:00 2001 From: ab Date: Wed, 12 Jun 2019 10:35:36 -0400 Subject: plus sign --- src/client/util/RichTextSchema.tsx | 26 +++++++++++++------------- src/client/views/nodes/FormattedTextBox.tsx | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index a29036f19..f10188c9e 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -28,9 +28,9 @@ export const nodes: { [index: string]: NodeSpec } = { star: { inline: true, - attrs: { oldtext: { default: "suhhhh" } }, + attrs: { oldtext: { default: "" } }, group: "inline", - toDOM() { return ["star", "🟊"]; }, + toDOM() { return ["star", "㊉"]; }, parseDOM: [{ tag: "star" }] }, @@ -426,17 +426,17 @@ export class ImageResizeView { } } -export class SummarizedView { - _collapsed: HTMLElement; - _selection: any; - constructor(node: any) { - this._collapsed = document.createElement("star"); - this._collapsed.onpointerdown = function (e: any) { - console.log("star pressed!"); - }; - - } -} +// export class SummarizedView { +// _collapsed: HTMLElement; +// _selection: any; +// constructor(node: any) { +// this._collapsed = document.createElement("star"); +// this._collapsed.onpointerdown = function (e: any) { +// console.log("star pressed!"); +// }; + +// } +// } // :: Schema // This schema rougly corresponds to the document schema used by // [CommonMark](http://commonmark.org/), minus the list elements, diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index b40c6d580..14597dbf1 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -16,7 +16,7 @@ import { DocumentManager } from "../../util/DocumentManager"; import { DragManager } from "../../util/DragManager"; import buildKeymap from "../../util/ProsemirrorKeymap"; import { inpRules } from "../../util/RichTextRules"; -import { SummarizedView, ImageResizeView, schema } from "../../util/RichTextSchema"; +import { ImageResizeView, schema } from "../../util/RichTextSchema"; import { SelectionManager } from "../../util/SelectionManager"; import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; import { TooltipTextMenu } from "../../util/TooltipTextMenu"; -- cgit v1.2.3-70-g09d2 From a4f5005fedae93bd4bb1529561acaa8d4f0474c5 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 12 Jun 2019 12:35:59 -0400 Subject: "fixed" prosemirror serialization of 'star' schema node --- src/client/util/RichTextSchema.tsx | 10 +++++----- src/client/util/TooltipTextMenu.tsx | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index db62f3ac1..d1282403f 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -90,6 +90,7 @@ export const nodes: { [index: string]: NodeSpec } = { attrs: { visibility: { default: false }, oldtext: { default: undefined }, + oldtextslice: { default: undefined }, oldtextlen: { default: 0 } }, @@ -502,10 +503,9 @@ export const schema = new Schema({ nodes, marks }); const fromJson = schema.nodeFromJSON; schema.nodeFromJSON = (json: any) => { - if (json.type !== "star") { - return fromJson(json); + let node = fromJson(json); + if (json.type === "star") { + node.attrs.oldtext = Slice.fromJSON(schema, node.attrs.oldtextslice); } - let x = fromJson(json); - x.attrs.oldtext = Slice.fromJSON(x.attrs.oldtext); - return x; + return node; } \ No newline at end of file diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index a2288a496..87a4c33a1 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -274,7 +274,7 @@ export class TooltipTextMenu { insertStar(state: EditorState, dispatch: any) { console.log("creating star..."); - let newNode = schema.nodes.star.create({ visibility: false, oldtext: state.selection.content(), oldtextlen: state.selection.to - state.selection.from }); + let newNode = schema.nodes.star.create({ visibility: false, oldtext: state.selection.content(), oldtextslice: state.selection.content().toJSON(), oldtextlen: state.selection.to - state.selection.from }); if (dispatch) { console.log(newNode.attrs.oldtext.toString()); dispatch(state.tr.replaceSelectionWith(newNode)); -- cgit v1.2.3-70-g09d2 From 22306895d56bcd59f7e993dee570b9b0722bd35d Mon Sep 17 00:00:00 2001 From: ab Date: Wed, 12 Jun 2019 13:11:30 -0400 Subject: summarized text is underlined --- src/client/util/RichTextSchema.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index d1282403f..70729c0d9 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -451,6 +451,7 @@ export class ImageResizeView { } export class SummarizedView { + // TODO: highlight _collapsed: HTMLElement; constructor(node: any, view: any, getPos: any) { this._collapsed = document.createElement("span"); @@ -473,9 +474,10 @@ export class SummarizedView { node.attrs.visibility = !node.attrs.visibility; console.log("content is invisible"); let y = getPos(); + let mark = view.state.schema.mark(view.state.schema.marks.underline); console.log("PASTING " + node.attrs.oldtext.toString()); view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, y + 1, y + 1))); - view.dispatch(view.state.tr.replaceSelection(node.attrs.oldtext)); + view.dispatch(view.state.tr.replaceSelection(node.attrs.oldtext).addMark(view.state.selection.from, view.state.selection.from + node.attrs.oldtextlen, mark)); //this._collapsed.textContent = "㊉"; } e.preventDefault(); -- cgit v1.2.3-70-g09d2 From f6bb5f269e04753669858e0994140984bc9d3915 Mon Sep 17 00:00:00 2001 From: ab Date: Wed, 12 Jun 2019 13:13:11 -0400 Subject: todo --- src/client/util/RichTextSchema.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 70729c0d9..2c3fd8320 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -451,7 +451,7 @@ export class ImageResizeView { } export class SummarizedView { - // TODO: highlight + // TODO: highlight text that is summarized. to find end of region, walk along mark _collapsed: HTMLElement; constructor(node: any, view: any, getPos: any) { this._collapsed = document.createElement("span"); -- cgit v1.2.3-70-g09d2 From d6abc733fa6f0bffdbceb4a7bd4c7f449607ea21 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 12 Jun 2019 13:51:28 -0400 Subject: don't want to parse all 'spans' as stars --- src/client/util/RichTextSchema.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/client/util/RichTextSchema.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 2c3fd8320..61ca4af5e 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -99,15 +99,15 @@ export const nodes: { [index: string]: NodeSpec } = { const attrs = { style: `width: 40px` }; return ["span", { ...node.attrs, ...attrs }]; }, - parseDOM: [{ - tag: "span", getAttrs(dom: any) { - return { - visibility: dom.getAttribute("visibility"), - oldtext: dom.getAttribute("oldtext"), - oldtextlen: dom.getAttribute("oldtextlen"), - } - } - }] + // parseDOM: [{ + // tag: "star", getAttrs(dom: any) { + // return { + // visibility: dom.getAttribute("visibility"), + // oldtext: dom.getAttribute("oldtext"), + // oldtextlen: dom.getAttribute("oldtextlen"), + // } + // } + // }] }, // :: NodeSpec An inline image (``) node. Supports `src`, // `alt`, and `href` attributes. The latter two default to the empty -- cgit v1.2.3-70-g09d2