diff options
Diffstat (limited to 'src/client/util')
-rw-r--r-- | src/client/util/DocumentManager.ts | 26 | ||||
-rw-r--r-- | src/client/util/DragManager.ts | 119 | ||||
-rw-r--r-- | src/client/util/RichTextSchema.tsx | 43 | ||||
-rw-r--r-- | src/client/util/Scripting.ts | 39 | ||||
-rw-r--r-- | src/client/util/ScrollBox.tsx | 4 | ||||
-rw-r--r-- | src/client/util/SelectionManager.ts | 21 | ||||
-rw-r--r-- | src/client/util/TooltipTextMenu.scss | 2 | ||||
-rw-r--r-- | src/client/util/TooltipTextMenu.tsx | 74 | ||||
-rw-r--r-- | src/client/util/Transform.ts | 42 | ||||
-rw-r--r-- | src/client/util/TypedEvent.ts | 4 | ||||
-rw-r--r-- | src/client/util/UndoManager.ts | 46 | ||||
-rw-r--r-- | src/client/util/type_decls.d | 2 |
12 files changed, 202 insertions, 220 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 341959936..f38b8ca75 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,7 +1,7 @@ -import React = require('react') +import React = require('react'); import { observer } from 'mobx-react'; import { observable, action, computed } from 'mobx'; -import { Document } from "../../fields/Document" +import { Document } from "../../fields/Document"; import { DocumentView } from '../views/nodes/DocumentView'; import { KeyStore } from '../../fields/KeyStore'; import { FieldWaiting } from '../../fields/Field'; @@ -29,7 +29,7 @@ export class DocumentManager { public getAllDocumentViews(collection: Document) { return this.DocumentViews.filter(dv => - dv.props.ContainingCollectionView && dv.props.ContainingCollectionView.props.Document.Id === collection.Id); + dv.props.ContainingCollectionView && dv.props.ContainingCollectionView.props.Document === collection); } public getDocumentView(toFind: Document): DocumentView | null { @@ -42,15 +42,15 @@ export class DocumentManager { let doc = view.props.Document; // if (view.props.ContainingCollectionView instanceof CollectionFreeFormView) { - if (Object.is(doc, toFind)) { + if (doc === toFind) { toReturn = view; return; } let docSrc = doc.GetT(KeyStore.Prototype, Document); - if (docSrc && docSrc != FieldWaiting && Object.is(docSrc, toFind)) { + if (docSrc && docSrc !== FieldWaiting && Object.is(docSrc, toFind)) { toReturn = view; } - }) + }); return (toReturn); } @@ -63,15 +63,15 @@ export class DocumentManager { let doc = view.props.Document; // if (view.props.ContainingCollectionView instanceof CollectionFreeFormView) { - if (Object.is(doc, toFind)) { + if (doc === toFind) { toReturn.push(view); } else { let docSrc = doc.GetT(KeyStore.Prototype, Document); - if (docSrc && docSrc != FieldWaiting && Object.is(docSrc, toFind)) { + if (docSrc && docSrc !== FieldWaiting && Object.is(docSrc, toFind)) { toReturn.push(view); } } - }) + }); return (toReturn); } @@ -80,14 +80,14 @@ export class DocumentManager { public get LinkedDocumentViews() { return DocumentManager.Instance.DocumentViews.reduce((pairs, dv) => { let linksList = dv.props.Document.GetT(KeyStore.LinkedToDocs, ListField); - if (linksList && linksList != FieldWaiting && linksList.Data.length) { + if (linksList && linksList !== FieldWaiting && linksList.Data.length) { pairs.push(...linksList.Data.reduce((pairs, link) => { if (link instanceof Document) { let linkToDoc = link.GetT(KeyStore.LinkedToDocs, Document); - if (linkToDoc && linkToDoc != FieldWaiting) { + if (linkToDoc && linkToDoc !== FieldWaiting) { DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { - pairs.push({ a: dv, b: docView1, l: link }) - }) + pairs.push({ a: dv, b: docView1, l: link }); + }); } } return pairs; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 0ee7ed2b3..d66c6e90f 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,39 +1,32 @@ import { action } from "mobx"; import { Document } from "../../fields/Document"; +import { emptyFunction } from "../../Utils"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; -import { CollectionView } from "../views/collections/CollectionView"; import { DocumentDecorations } from "../views/DocumentDecorations"; +import { Main } from "../views/Main"; import { DocumentView } from "../views/nodes/DocumentView"; +import globalStyles from "../views/_global_variables"; +// import globalStyleVariables from "../views/_global_variables.scss"; // bcz: why doesn't this work? -export function setupDrag( - _reference: React.RefObject<HTMLDivElement>, - docFunc: () => Document, - removeFunc: (containingCollection: CollectionView) => void = () => { }, - copyOnDrop: boolean = false -) { - let onRowMove = action( - (e: PointerEvent): void => { - e.stopPropagation(); - e.preventDefault(); +export function setupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: () => Document, moveFunc?: DragManager.MoveFunction, copyOnDrop: boolean = false) { + let onRowMove = action((e: PointerEvent): void => { + e.stopPropagation(); + e.preventDefault(); - // TODO: bcz -- this needs to have a drag threshold so that it doesn't trigger when just selecting. - document.removeEventListener("pointermove", onRowMove); - document.removeEventListener("pointerup", onRowUp); - var dragData = new DragManager.DocumentDragData([docFunc()]); - dragData.copyOnDrop = copyOnDrop; - dragData.removeDocument = removeFunc; - DragManager.StartDocumentDrag([_reference.current!], dragData, e.x, e.y); - } - ); - let onRowUp = action( - (e: PointerEvent): void => { - document.removeEventListener("pointermove", onRowMove); - document.removeEventListener("pointerup", onRowUp); - } - ); + document.removeEventListener("pointermove", onRowMove); + document.removeEventListener('pointerup', onRowUp); + var dragData = new DragManager.DocumentDragData([docFunc()]); + dragData.copyOnDrop = copyOnDrop; + dragData.moveDocument = moveFunc; + DragManager.StartDocumentDrag([_reference.current!], dragData, e.x, e.y); + }); + let onRowUp = action((e: PointerEvent): void => { + document.removeEventListener("pointermove", onRowMove); + document.removeEventListener('pointerup', onRowUp); + }); let onItemDown = (e: React.PointerEvent) => { // if (this.props.isSelected() || this.props.isTopMost) { - if (e.button == 0) { + if (e.button === 0) { e.stopPropagation(); if (e.shiftKey) { CollectionDockingView.Instance.StartOtherDrag([docFunc()], e); @@ -104,7 +97,7 @@ export namespace DragManager { "Element is already droppable, can't make it droppable again" ); } - element.dataset["canDrop"] = "true"; + element.dataset.canDrop = "true"; const handler = (e: Event) => { const ce = e as CustomEvent<DropEvent>; options.handlers.drop(e, ce.detail); @@ -112,10 +105,11 @@ export namespace DragManager { element.addEventListener("dashOnDrop", handler); return () => { element.removeEventListener("dashOnDrop", handler); - delete element.dataset["canDrop"]; + delete element.dataset.canDrop; }; } + export type MoveFunction = (document: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean; export class DocumentDragData { constructor(dragDoc: Document[]) { this.draggedDocuments = dragDoc; @@ -127,24 +121,13 @@ export namespace DragManager { yOffset?: number; aliasOnDrop?: boolean; copyOnDrop?: boolean; - removeDocument?: (collectionDrop: CollectionView) => void; + moveDocument?: MoveFunction; [id: string]: any; } - export function StartDocumentDrag( - eles: HTMLElement[], - dragData: DocumentDragData, - downX: number, - downY: number, - options?: DragOptions - ) { + export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { StartDrag(eles, dragData, downX, downY, options, - (dropData: { [id: string]: any }) => - (dropData.droppedDocuments = dragData.aliasOnDrop - ? dragData.draggedDocuments.map(d => d.CreateAlias()) - : dragData.copyOnDrop ? dragData.draggedDocuments.map(d => d.Copy(true) as Document) : - dragData.draggedDocuments) - ); + (dropData: { [id: string]: any }) => (dropData.droppedDocuments = dragData.aliasOnDrop ? dragData.draggedDocuments.map(d => d.CreateAlias()) : dragData.copyOnDrop ? dragData.draggedDocuments.map(d => d.Copy(true) as Document) : dragData.draggedDocuments)); } export class LinkDragData { @@ -155,26 +138,18 @@ export namespace DragManager { linkSourceDocumentView: DocumentView; [id: string]: any; } - export function StartLinkDrag( - ele: HTMLElement, - dragData: LinkDragData, - downX: number, downY: number, - options?: DragOptions - ) { + + export function StartLinkDrag(ele: HTMLElement, dragData: LinkDragData, downX: number, downY: number, options?: DragOptions) { StartDrag([ele], dragData, downX, downY, options); } - function StartDrag( - eles: HTMLElement[], - dragData: { [id: string]: any }, - downX: number, downY: number, - options?: DragOptions, - finishDrag?: (dropData: { [id: string]: any }) => void - ) { + + function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: { [id: string]: any }) => void) { if (!dragDiv) { dragDiv = document.createElement("div"); dragDiv.className = "dragManager-dragDiv"; DragManager.Root().appendChild(dragDiv); } + Main.Instance.SetTextDoc(); let scaleXs: number[] = []; let scaleYs: number[] = []; @@ -203,7 +178,7 @@ export namespace DragManager { dragElement.style.bottom = ""; dragElement.style.left = "0"; dragElement.style.transformOrigin = "0 0"; - dragElement.style.zIndex = "1000"; + dragElement.style.zIndex = globalStyles.contextMenuZindex;// "1000"; dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; dragElement.style.width = `${rect.width / scaleX}px`; dragElement.style.height = `${rect.height / scaleY}px`; @@ -217,11 +192,11 @@ export namespace DragManager { // let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); // if (pdfBox && pdfBox.childElementCount && thumbnail) { // let img = new Image(); - // img!.src = thumbnail.toString(); - // img!.style.position = "absolute"; - // img!.style.width = `${rect.width / scaleX}px`; - // img!.style.height = `${rect.height / scaleY}px`; - // pdfBox.replaceChild(img!, pdfBox.children[0]); + // img.src = thumbnail.toString(); + // img.style.position = "absolute"; + // img.style.width = `${rect.width / scaleX}px`; + // img.style.height = `${rect.height / scaleY}px`; + // pdfBox.replaceChild(img, pdfBox.children[0]) // } // } @@ -244,17 +219,19 @@ export namespace DragManager { const moveHandler = (e: PointerEvent) => { e.stopPropagation(); e.preventDefault(); - if (dragData instanceof DocumentDragData) + if (dragData instanceof DocumentDragData) { dragData.aliasOnDrop = e.ctrlKey || e.altKey; + } if (e.shiftKey) { abortDrag(); CollectionDockingView.Instance.StartOtherDrag(docs, { pageX: e.pageX, pageY: e.pageY, - preventDefault: () => { }, + preventDefault: emptyFunction, button: 0 }); } + //TODO: Why can't we use e.movementX and e.movementY? let moveX = e.pageX - lastX; let moveY = e.pageY - lastY; lastX = e.pageX; @@ -279,13 +256,7 @@ export namespace DragManager { document.addEventListener("pointerup", upHandler); } - function FinishDrag( - dragEles: HTMLElement[], - e: PointerEvent, - dragData: { [index: string]: any }, - options?: DragOptions, - finishDrag?: (dragData: { [index: string]: any }) => void - ) { + function FinishDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (dragData: { [index: string]: any }) => void) { let removed = dragEles.map(dragEle => { let parent = dragEle.parentElement; if (parent) parent.removeChild(dragEle); @@ -293,9 +264,9 @@ export namespace DragManager { }); const target = document.elementFromPoint(e.x, e.y); removed.map(r => { - let dragEle: HTMLElement = r[0]!; - let parent: HTMLElement | null = r[1]; - if (parent) parent.appendChild(dragEle); + let dragEle = r[0]; + let parent = r[1]; + if (parent && dragEle) parent.appendChild(dragEle); }); if (target) { if (finishDrag) finishDrag(dragData); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 765ac0ae3..dac4be3d6 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -1,13 +1,14 @@ 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 { redo, undo } from 'prosemirror-history' -import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list' +import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType } from "prosemirror-model"; +import { joinUp, lift, setBlockType, toggleMark, wrapIn } 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 { EditorView, } from "prosemirror-view"; const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], - preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0] + preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; + // :: Object // [Specs](#model.NodeSpec) for the nodes defined in this schema. @@ -23,7 +24,7 @@ export const nodes: { [index: string]: NodeSpec } = { content: "inline*", group: "block", parseDOM: [{ tag: "p" }], - toDOM() { return pDOM } + toDOM() { return pDOM; } }, // :: NodeSpec A blockquote (`<blockquote>`) wrapping one or more blocks. @@ -32,14 +33,14 @@ export const nodes: { [index: string]: NodeSpec } = { group: "block", defining: true, parseDOM: [{ tag: "blockquote" }], - toDOM() { return blockquoteDOM } + toDOM() { return blockquoteDOM; } }, // :: NodeSpec A horizontal rule (`<hr>`). horizontal_rule: { group: "block", parseDOM: [{ tag: "hr" }], - toDOM() { return hrDOM } + toDOM() { return hrDOM; } }, // :: NodeSpec A heading textblock, with a `level` attribute that @@ -56,7 +57,7 @@ export const nodes: { [index: string]: NodeSpec } = { { tag: "h4", attrs: { level: 4 } }, { tag: "h5", attrs: { level: 5 } }, { tag: "h6", attrs: { level: 6 } }], - toDOM(node: any) { return ["h" + node.attrs.level, 0] } + toDOM(node: any) { return ["h" + node.attrs.level, 0]; } }, // :: NodeSpec A code listing. Disallows marks or non-text inline @@ -69,7 +70,7 @@ export const nodes: { [index: string]: NodeSpec } = { code: true, defining: true, parseDOM: [{ tag: "pre", preserveWhitespace: "full" }], - toDOM() { return preDOM } + toDOM() { return preDOM; } }, // :: NodeSpec The text node. @@ -95,10 +96,10 @@ export const nodes: { [index: string]: NodeSpec } = { src: dom.getAttribute("src"), title: dom.getAttribute("title"), alt: dom.getAttribute("alt") - } + }; } }], - toDOM(node: any) { return ["img", node.attrs] } + toDOM(node: any) { return ["img", node.attrs]; } }, // :: NodeSpec A hard line break, represented in the DOM as `<br>`. @@ -107,7 +108,7 @@ export const nodes: { [index: string]: NodeSpec } = { group: "inline", selectable: false, parseDOM: [{ tag: "br" }], - toDOM() { return brDOM } + toDOM() { return brDOM; } }, ordered_list: { @@ -135,7 +136,7 @@ export const nodes: { [index: string]: NodeSpec } = { ...listItem, content: 'paragraph block*' } -} +}; const emDOM: DOMOutputSpecArray = ["em", 0]; const strongDOM: DOMOutputSpecArray = ["strong", 0]; @@ -155,17 +156,17 @@ export const marks: { [index: string]: MarkSpec } = { inclusive: false, parseDOM: [{ tag: "a[href]", getAttrs(dom: any) { - return { href: dom.getAttribute("href"), title: dom.getAttribute("title") } + return { href: dom.getAttribute("href"), title: dom.getAttribute("title") }; } }], - toDOM(node: any) { return ["a", node.attrs, 0] } + toDOM(node: any) { return ["a", node.attrs, 0]; } }, // :: MarkSpec An emphasis mark. Rendered as an `<em>` element. // Has parse rules that also match `<i>` and `font-style: italic`. em: { parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }], - toDOM() { return emDOM } + toDOM() { return emDOM; } }, // :: MarkSpec A strong mark. Rendered as `<strong>`, parse rules @@ -174,7 +175,7 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [{ tag: "strong" }, { tag: "b" }, { style: "font-weight" }], - toDOM() { return strongDOM } + toDOM() { return strongDOM; } }, underline: { @@ -220,7 +221,7 @@ export const marks: { [index: string]: MarkSpec } = { // :: MarkSpec Code font mark. Represented as a `<code>` element. code: { parseDOM: [{ tag: "code" }], - toDOM() { return codeDOM } + toDOM() { return codeDOM; } }, @@ -317,7 +318,7 @@ export const marks: { [index: string]: MarkSpec } = { style: 'font-size: 72px;' }] }, -} +}; // :: Schema // This schema rougly corresponds to the document schema used by @@ -327,4 +328,4 @@ export const marks: { [index: string]: MarkSpec } = { // // To reuse elements from this schema, extend or read from its // `spec.nodes` and `spec.marks` [properties](#model.Schema.spec). -export const schema = new Schema({ nodes, marks })
\ No newline at end of file +export const schema = new Schema({ nodes, marks });
\ No newline at end of file diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 7c0649a6a..9015f21cf 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -14,7 +14,7 @@ import { ListField } from "../../fields/ListField"; // import * as typescriptes5 from '!!raw-loader!../../../node_modules/typescript/lib/lib.es5.d.ts' // @ts-ignore -import * as typescriptlib from '!!raw-loader!./type_decls.d' +import * as typescriptlib from '!!raw-loader!./type_decls.d'; import { Documents } from "../documents/Documents"; import { Key } from "../../fields/Key"; @@ -30,8 +30,10 @@ export interface ScriptError { export type ScriptResult = ScriptSucccess | ScriptError; -export interface CompileSuccess { - compiled: true; +export interface CompiledScript { + readonly compiled: true; + readonly originalScript: string; + readonly options: Readonly<ScriptOptions>; run(args?: { [name: string]: any }): ScriptResult; } @@ -40,17 +42,17 @@ export interface CompileError { errors: any[]; } -export type CompiledScript = CompileSuccess | CompileError; +export type CompileResult = CompiledScript | CompileError; -function Run(script: string | undefined, customParams: string[], diagnostics: any[]): CompiledScript { - const errors = diagnostics.some(diag => diag.category == ts.DiagnosticCategory.Error); +function Run(script: string | undefined, customParams: string[], diagnostics: any[], originalScript: string, options: ScriptOptions): CompileResult { + const errors = diagnostics.some(diag => diag.category === ts.DiagnosticCategory.Error); if (errors || !script) { return { compiled: false, errors: diagnostics }; } let fieldTypes = [Document, NumberField, TextField, ImageField, RichTextField, ListField, Key]; let paramNames = ["KeyStore", "Documents", ...fieldTypes.map(fn => fn.name)]; - let params: any[] = [KeyStore, Documents, ...fieldTypes] + let params: any[] = [KeyStore, Documents, ...fieldTypes]; let compiledFunction = new Function(...paramNames, `return ${script}`); let run = (args: { [name: string]: any } = {}): ScriptResult => { let argsArray: any[] = []; @@ -60,15 +62,15 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an } argsArray.push(args[name]); } - let thisParam = args["this"]; + let thisParam = args.this; try { const result = compiledFunction.apply(thisParam, params).apply(thisParam, argsArray); return { success: true, result }; } catch (error) { return { success: false, error }; } - } - return { compiled: true, run }; + }; + return { compiled: true, run, originalScript, options }; } interface File { @@ -90,14 +92,14 @@ class ScriptingCompilerHost { } // getDefaultLibFileName(options: ts.CompilerOptions): string { getDefaultLibFileName(options: any): string { - return 'node_modules/typescript/lib/lib.d.ts' // No idea what this means... + return 'node_modules/typescript/lib/lib.d.ts'; // No idea what this means... } writeFile(fileName: string, content: string) { const file = this.files.find(file => file.fileName === fileName); if (file) { file.content = content; } else { - this.files.push({ fileName, content }) + this.files.push({ fileName, content }); } } getCurrentDirectory(): string { @@ -130,7 +132,7 @@ export interface ScriptOptions { params?: { [name: string]: string }; } -export function CompileScript(script: string, { requiredType = "", addReturn = false, params = {} }: ScriptOptions = {}): CompiledScript { +export function CompileScript(script: string, { requiredType = "", addReturn = false, params = {} }: ScriptOptions = {}): CompileResult { let host = new ScriptingCompilerHost; let paramArray: string[] = []; if ("this" in params) { @@ -140,7 +142,10 @@ export function CompileScript(script: string, { requiredType = "", addReturn = f if (key === "this") continue; paramArray.push(key); } - let paramString = paramArray.map(key => `${key}: ${params[key]}`).join(", "); + let paramString = paramArray.map(key => { + const val = params[key]; + return `${key}: ${val}`; + }).join(", "); let funcScript = `(function(${paramString})${requiredType ? `: ${requiredType}` : ''} { ${addReturn ? `return ${script};` : script} })`; @@ -152,7 +157,7 @@ export function CompileScript(script: string, { requiredType = "", addReturn = f let diagnostics = ts.getPreEmitDiagnostics(program).concat(testResult.diagnostics); - return Run(outputText, paramArray, diagnostics); + return Run(outputText, paramArray, diagnostics, script, { requiredType, addReturn, params }); } export function OrLiteralType(returnType: string): string { @@ -160,9 +165,9 @@ export function OrLiteralType(returnType: string): string { } export function ToField(data: any): Opt<Field> { - if (typeof data == "string") { + if (typeof data === "string") { return new TextField(data); - } else if (typeof data == "number") { + } else if (typeof data === "number") { return new NumberField(data); } return undefined; diff --git a/src/client/util/ScrollBox.tsx b/src/client/util/ScrollBox.tsx index b6b088170..a209874a3 100644 --- a/src/client/util/ScrollBox.tsx +++ b/src/client/util/ScrollBox.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); export class ScrollBox extends React.Component { onWheel = (e: React.WheelEvent) => { @@ -16,6 +16,6 @@ export class ScrollBox extends React.Component { }} onWheel={this.onWheel}> {this.props.children} </div> - ) + ); } }
\ No newline at end of file diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 79d4ceb25..2fa45a086 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -12,13 +12,21 @@ export namespace SelectionManager { SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { // if doc is not in SelectedDocuments, add it if (!ctrlPressed) { - manager.SelectedDocuments = []; + this.DeselectAll(); } if (manager.SelectedDocuments.indexOf(doc) === -1) { manager.SelectedDocuments.push(doc); + doc.props.onActiveChanged(true); } } + + @action + DeselectAll(): void { + manager.SelectedDocuments.map(dv => dv.props.onActiveChanged(false)); + manager.SelectedDocuments = []; + Main.Instance.SetTextDoc(); + } } const manager = new Manager(); @@ -34,14 +42,13 @@ export namespace SelectionManager { export function DeselectAll(except?: Document): void { let found: DocumentView | undefined = undefined; if (except) { - for (let i = 0; i < manager.SelectedDocuments.length; i++) { - let view = manager.SelectedDocuments[i]; - if (view.props.Document == except) found = view; + for (const view of manager.SelectedDocuments) { + if (view.props.Document === except) found = view; } } - manager.SelectedDocuments.length = 0; - if (found) manager.SelectedDocuments.push(found); - Main.Instance.SetTextDoc(undefined, undefined); + + manager.DeselectAll(); + if (found) manager.SelectDoc(found, false); } export function SelectedDocuments(): Array<DocumentView> { diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index b23074239..9111d60f1 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -238,7 +238,7 @@ .tooltipMenu { position: absolute; - z-index: 20; + z-index: 200; background: $dark-color; border: 1px solid silver; border-radius: 4px; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 777abe030..3869db41a 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -10,14 +10,16 @@ import { Schema, NodeType, MarkType } from "prosemirror-model"; import React = require("react"); import "./TooltipTextMenu.scss"; const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); -import { library } from '@fortawesome/fontawesome-svg-core' -import { wrapInList, bulletList, liftListItem, listItem } from 'prosemirror-schema-list' +import { library } from '@fortawesome/fontawesome-svg-core'; +import { wrapInList, bulletList, liftListItem, listItem } from 'prosemirror-schema-list'; import { faListUl, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { FieldViewProps } from "../views/nodes/FieldView"; +import { throwStatement } from "babel-types"; -const SVG = "http://www.w3.org/2000/svg" +const SVG = "http://www.w3.org/2000/svg"; //appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc. export class TooltipTextMenu { @@ -27,9 +29,11 @@ export class TooltipTextMenu { private view: EditorView; private fontStyles: MarkType[]; private fontSizes: MarkType[]; + private editorProps: FieldViewProps; - constructor(view: EditorView) { + constructor(view: EditorView, editorProps: FieldViewProps) { this.view = view; + this.editorProps = editorProps; this.tooltip = document.createElement("div"); this.tooltip.className = "tooltipMenu"; @@ -48,7 +52,7 @@ export class TooltipTextMenu { { command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript") }, { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, { command: lift, dom: this.icon("<", "lift") }, - ] + ]; //add menu items items.forEach(({ dom, command }) => { this.tooltip.appendChild(dom); @@ -58,7 +62,7 @@ export class TooltipTextMenu { e.preventDefault(); view.focus(); command(view.state, view.dispatch, view); - }) + }); }); @@ -71,7 +75,7 @@ export class TooltipTextMenu { schema.marks.comicSans, schema.marks.tahoma, schema.marks.impact, - ] + ]; this.fontSizes = [ schema.marks.p10, schema.marks.p12, @@ -80,7 +84,7 @@ export class TooltipTextMenu { schema.marks.p32, schema.marks.p48, schema.marks.p72, - ] + ]; this.addFontDropdowns(); this.update(view, undefined); @@ -97,7 +101,7 @@ export class TooltipTextMenu { this.dropdownBtn("ComicSans", "font-family: Comic Sans MS, cursive, sans-serif; width: 120px;", schema.marks.comicSans, this.view, this.changeToMarkInGroup, this.fontStyles), this.dropdownBtn("Tahoma", "font-family: Tahoma, Geneva, sans-serif; width: 120px;", schema.marks.tahoma, this.view, this.changeToMarkInGroup, this.fontStyles), this.dropdownBtn("Impact", "font-family: Impact, Charcoal, sans-serif; width: 120px;", schema.marks.impact, this.view, this.changeToMarkInGroup, this.fontStyles), - ] + ]; let fontSizeBtns = [ this.dropdownBtn("10", "width: 50px;", schema.marks.p10, this.view, this.changeToMarkInGroup, this.fontSizes), @@ -107,7 +111,7 @@ export class TooltipTextMenu { this.dropdownBtn("32", "width: 50px;", schema.marks.p32, this.view, this.changeToMarkInGroup, this.fontSizes), this.dropdownBtn("48", "width: 50px;", schema.marks.p48, this.view, this.changeToMarkInGroup, this.fontSizes), this.dropdownBtn("72", "width: 50px;", schema.marks.p72, this.view, this.changeToMarkInGroup, this.fontSizes), - ] + ]; //dropdown to hold font btns let dd_fontStyle = new Dropdown(cut(fontBtns), { label: "Font Style", css: "color:white;" }) as MenuItem; @@ -130,13 +134,13 @@ export class TooltipTextMenu { dispatch(state.tr.removeStoredMark(type)); } } else { - let has = false, tr = state.tr + let has = false, tr = state.tr; for (let i = 0; !has && i < ranges.length; i++) { - let { $from, $to } = ranges[i] - has = state.doc.rangeHasMark($from.pos, $to.pos, type) + let { $from, $to } = ranges[i]; + has = state.doc.rangeHasMark($from.pos, $to.pos, type); } - for (let i = 0; i < ranges.length; i++) { - let { $from, $to } = ranges[i] + for (let i of ranges) { + let { $from, $to } = i; if (has) { toggleMark(type)(view.state, view.dispatch, view); } @@ -174,12 +178,12 @@ export class TooltipTextMenu { //method for checking whether node can be inserted canInsert(state: EditorState, nodeType: NodeType<Schema<string, string>>) { - let $from = state.selection.$from + let $from = state.selection.$from; for (let d = $from.depth; d >= 0; d--) { - let index = $from.index(d) - if ($from.node(d).canReplaceWith(index, index, nodeType)) return true + let index = $from.index(d); + if ($from.node(d).canReplaceWith(index, index, nodeType)) return true; } - return false + return false; } @@ -206,38 +210,38 @@ export class TooltipTextMenu { return { command: setBlockType(schema.nodes.heading, { level }), dom: this.icon("H" + level, "heading") - } + }; } //updates the tooltip menu when the selection changes update(view: EditorView, lastState: EditorState | undefined) { - let state = view.state + let state = view.state; // Don't do anything if the document/selection didn't change if (lastState && lastState.doc.eq(state.doc) && - lastState.selection.eq(state.selection)) return + lastState.selection.eq(state.selection)) return; // Hide the tooltip if the selection is empty if (state.selection.empty) { - this.tooltip.style.display = "none" - return + this.tooltip.style.display = "none"; + return; } // Otherwise, reposition it and update its content - this.tooltip.style.display = "" - let { from, to } = state.selection - let start = view.coordsAtPos(from), end = view.coordsAtPos(to) + this.tooltip.style.display = ""; + let { from, to } = state.selection; + let start = view.coordsAtPos(from), end = view.coordsAtPos(to); // The box in which the tooltip is positioned, to use as base - let box = this.tooltip.offsetParent!.getBoundingClientRect() + let box = this.tooltip.offsetParent!.getBoundingClientRect(); // Find a center-ish x position from the selection endpoints (when // crossing lines, end may be more to the left) - let left = Math.max((start.left + end.left) / 2, start.left + 3) - this.tooltip.style.left = (left - box.left) + "px" - //let width = Math.abs(start.left - end.left) / 2; - let width = 220; + let left = Math.max((start.left + end.left) / 2, start.left + 3); + this.tooltip.style.left = (left - box.left) * this.editorProps.ScreenToLocalTransform().Scale + "px"; + let width = Math.abs(start.left - end.left) / 2 * this.editorProps.ScreenToLocalTransform().Scale; let mid = Math.min(start.left, end.left) + width; - this.tooltip.style.width = width + "px"; - this.tooltip.style.bottom = (box.bottom - start.top) + "px"; + + this.tooltip.style.width = 220 + "px"; + this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px"; } - destroy() { this.tooltip.remove() } + destroy() { this.tooltip.remove(); } } diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts index 060c5da82..e9170ec36 100644 --- a/src/client/util/Transform.ts +++ b/src/client/util/Transform.ts @@ -3,7 +3,7 @@ export class Transform { private _translateY: number = 0; private _scale: number = 1; - static get Identity(): Transform { + static Identity(): Transform { return new Transform(0, 0, 1); } @@ -62,33 +62,19 @@ export class Transform { return this; } - translated = (x: number, y: number): Transform => { - return this.copy().translate(x, y); - } + translated = (x: number, y: number): Transform => this.copy().translate(x, y); - preTranslated = (x: number, y: number): Transform => { - return this.copy().preTranslate(x, y); - } + preTranslated = (x: number, y: number): Transform => this.copy().preTranslate(x, y); - scaled = (scale: number): Transform => { - return this.copy().scale(scale); - } + scaled = (scale: number): Transform => this.copy().scale(scale); - scaledAbout = (scale: number, x: number, y: number): Transform => { - return this.copy().scaleAbout(scale, x, y); - } + scaledAbout = (scale: number, x: number, y: number): Transform => this.copy().scaleAbout(scale, x, y); - preScaled = (scale: number): Transform => { - return this.copy().preScale(scale); - } + preScaled = (scale: number): Transform => this.copy().preScale(scale); - transformed = (transform: Transform): Transform => { - return this.copy().transform(transform); - } + transformed = (transform: Transform): Transform => this.copy().transform(transform); - preTransformed = (transform: Transform): Transform => { - return this.copy().preTransform(transform); - } + preTransformed = (transform: Transform): Transform => this.copy().preTransform(transform); transformPoint = (x: number, y: number): [number, number] => { x *= this._scale; @@ -98,9 +84,7 @@ export class Transform { return [x, y]; } - transformDirection = (x: number, y: number): [number, number] => { - return [x * this._scale, y * this._scale]; - } + transformDirection = (x: number, y: number): [number, number] => [x * this._scale, y * this._scale]; transformBounds(x: number, y: number, width: number, height: number): { x: number, y: number, width: number, height: number } { [x, y] = this.transformPoint(x, y); @@ -108,12 +92,8 @@ export class Transform { return { x, y, width, height }; } - inverse = () => { - return new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale) - } + inverse = () => new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale); - copy = () => { - return new Transform(this._translateX, this._translateY, this._scale); - } + copy = () => new Transform(this._translateX, this._translateY, this._scale); }
\ No newline at end of file diff --git a/src/client/util/TypedEvent.ts b/src/client/util/TypedEvent.ts index 0714a7f5c..532ba78eb 100644 --- a/src/client/util/TypedEvent.ts +++ b/src/client/util/TypedEvent.ts @@ -36,7 +36,5 @@ export class TypedEvent<T> { this.listenersOncer = []; } - pipe = (te: TypedEvent<T>): Disposable => { - return this.on((e) => te.emit(e)); - } + pipe = (te: TypedEvent<T>): Disposable => this.on((e) => te.emit(e)); }
\ No newline at end of file diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts index eb13ff1ee..27aed4bac 100644 --- a/src/client/util/UndoManager.ts +++ b/src/client/util/UndoManager.ts @@ -1,5 +1,5 @@ import { observable, action } from "mobx"; -import 'source-map-support/register' +import 'source-map-support/register'; import { Without } from "../../Utils"; import { string } from "prop-types"; @@ -31,11 +31,24 @@ function propertyDecorator(target: any, key: string | symbol) { batch.end(); } } - }) + }); } - }) + }); } -export function undoBatch(target: any, key: string | symbol, descriptor?: TypedPropertyDescriptor<any>): any { + +export function undoBatch(target: any, key: string | symbol, descriptor?: TypedPropertyDescriptor<any>): any; +export function undoBatch(fn: (...args: any[]) => any): (...args: any[]) => any; +export function undoBatch(target: any, key?: string | symbol, descriptor?: TypedPropertyDescriptor<any>): any { + if (!key) { + return function () { + let batch = UndoManager.StartBatch(""); + try { + return target.apply(undefined, arguments); + } finally { + batch.end(); + } + }; + } if (!descriptor) { propertyDecorator(target, key); return; @@ -45,11 +58,11 @@ export function undoBatch(target: any, key: string | symbol, descriptor?: TypedP descriptor.value = function (...args: any[]) { let batch = UndoManager.StartBatch(getBatchName(target, key)); try { - return oldFunction.apply(this, args) + return oldFunction.apply(this, args); } finally { batch.end(); } - } + }; return descriptor; } @@ -104,8 +117,8 @@ export namespace UndoManager { EndBatch(cancel); } - end = () => { this.dispose(false); } - cancel = () => { this.dispose(true); } + end = () => { this.dispose(false); }; + cancel = () => { this.dispose(true); }; } export function StartBatch(batchName: string): Batch { @@ -125,12 +138,15 @@ export namespace UndoManager { redoStack.length = 0; currentBatch = undefined; } - }) + }); export function RunInBatch(fn: () => void, batchName: string) { let batch = StartBatch(batchName); - fn(); - batch.end(); + try { + fn(); + } finally { + batch.end(); + } } export const Undo = action(() => { @@ -150,7 +166,7 @@ export namespace UndoManager { undoing = false; redoStack.push(commands); - }) + }); export const Redo = action(() => { if (redoStack.length === 0) { @@ -163,12 +179,12 @@ export namespace UndoManager { } undoing = true; - for (let i = 0; i < commands.length; i++) { - commands[i].redo(); + for (const command of commands) { + command.redo(); } undoing = false; undoStack.push(commands); - }) + }); }
\ No newline at end of file diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d index 4f69053b1..47c3481b2 100644 --- a/src/client/util/type_decls.d +++ b/src/client/util/type_decls.d @@ -181,7 +181,7 @@ declare class Key extends Field { Copy(): Field; ToScriptString(): string; } -declare type FIELD_WAITING = "<Waiting>"; +declare type FIELD_WAITING = null; declare type Opt<T> = T | undefined; declare type FieldValue<T> = Opt<T> | FIELD_WAITING; // @ts-ignore |