From b29a0d1cef60b55f609fcd94ad38232ae557e681 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Thu, 16 May 2019 18:32:57 -0400 Subject: Fixed linter errors --- src/client/util/DragManager.ts | 2 +- src/client/util/RichTextSchema.tsx | 16 ++++++++-------- src/client/util/TooltipTextMenu.tsx | 13 +++++++------ 3 files changed, 16 insertions(+), 15 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 26da34e67..05eb5c38a 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -41,7 +41,7 @@ export function SetupDrag(_reference: React.RefObject, docFunc: () export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: number, sourceDoc: Doc) { let srcTarg = sourceDoc.proto; let draggedDocs: Doc[] = []; - let draggedFromDocs: Doc[] = [] + let draggedFromDocs: Doc[] = []; if (srcTarg) { let linkToDocs = await DocListCastAsync(srcTarg.linkedToDocs); let linkFromDocs = await DocListCastAsync(srcTarg.linkedFromDocs); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index c0e6f7899..3e3e98206 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -97,13 +97,13 @@ export const nodes: { [index: string]: NodeSpec } = { title: dom.getAttribute("title"), alt: dom.getAttribute("alt"), width: Math.min(100, Number(dom.getAttribute("width"))), - } + }; } }], // 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 }] + const attrs = { style: `width: ${node.attrs.width}` }; + return ["img", { ...node.attrs, ...attrs }]; } }, @@ -375,7 +375,7 @@ export class ImageResizeView { const currentX = e.pageX; const diffInPx = currentX - startX; self._outer.style.width = `${startWidth + diffInPx}`; - } + }; const onpointerup = () => { document.removeEventListener("pointermove", onpointermove); @@ -384,11 +384,11 @@ export class ImageResizeView { 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) - } + document.addEventListener("pointermove", onpointermove); + document.addEventListener("pointerup", onpointerup); + }; this._outer.appendChild(this._handle); this._outer.appendChild(this._img); diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 6eb654319..223921428 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -175,7 +175,7 @@ export class TooltipTextMenu { this.linkText.style.width = "150px"; this.linkText.style.overflow = "hidden"; this.linkText.style.color = "white"; - this.linkText.onpointerdown = (e: PointerEvent) => { e.stopPropagation(); } + this.linkText.onpointerdown = (e: PointerEvent) => { e.stopPropagation(); }; let linkBtn = document.createElement("div"); linkBtn.textContent = ">>"; linkBtn.style.width = "20px"; @@ -192,8 +192,9 @@ export class TooltipTextMenu { let docid = href.replace(DocServer.prepend("/doc/"), ""); DocServer.GetRefField(docid).then(action((f: Opt) => { if (f instanceof Doc) { - if (DocumentManager.Instance.getDocumentView(f)) + if (DocumentManager.Instance.getDocumentView(f)) { DocumentManager.Instance.getDocumentView(f)!.props.focus(f); + } else CollectionDockingView.Instance.AddRightSplit(f); } })); @@ -201,7 +202,7 @@ export class TooltipTextMenu { e.stopPropagation(); e.preventDefault(); } - } + }; this.linkDrag = document.createElement("img"); this.linkDrag.src = "https://seogurusnyc.com/wp-content/uploads/2016/12/link-1.png"; this.linkDrag.style.width = "20px"; @@ -216,12 +217,12 @@ export class TooltipTextMenu { { handlers: { dragComplete: action(() => { - let m = dragData.droppedDocuments as Doc[]; + let m = dragData.droppedDocuments; this.makeLink(DocServer.prepend("/doc/" + m[0][Id])); }), }, hideSource: false - }) + }); }; this.linkEditor.appendChild(this.linkDrag); this.linkEditor.appendChild(this.linkText); @@ -239,7 +240,7 @@ export class TooltipTextMenu { e.stopPropagation(); e.preventDefault(); } - } + }; this.tooltip.appendChild(this.linkEditor); } -- cgit v1.2.3-70-g09d2 From 6e65b1e32eb972358d9c8dbd7f8d984d3baefc4b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 16 May 2019 22:56:19 -0400 Subject: fixed links so that you can adjust the pan location of a collection when its a link endoint --- src/client/util/DocumentManager.ts | 5 +++-- src/client/util/DragManager.ts | 2 +- src/client/util/TooltipTextMenu.tsx | 1 - src/client/views/Main.tsx | 2 +- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 3 ++- src/client/views/nodes/DocumentView.tsx | 11 ++++++----- src/client/views/nodes/FormattedTextBox.tsx | 4 +--- src/client/views/nodes/LinkBox.tsx | 2 +- src/client/views/nodes/LinkMenu.tsx | 5 ++--- src/new_fields/Doc.ts | 10 ++++++---- 10 files changed, 23 insertions(+), 22 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 51f5fbe9f..c6962ad8d 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -110,7 +110,8 @@ export class DocumentManager { } @undoBatch - public jumpToDocument = async (doc: Doc): Promise => { + public jumpToDocument = async (docDelegate: Doc, makeCopy: boolean = true): Promise => { + let doc = docDelegate.proto ? docDelegate.proto : docDelegate; const page = NumCast(doc.page, undefined); const contextDoc = await Cast(doc.annotationOn, Doc); if (contextDoc) { @@ -122,7 +123,7 @@ export class DocumentManager { docView.props.focus(docView.props.Document); } else { if (!contextDoc) { - CollectionDockingView.Instance.AddRightSplit(Doc.MakeDelegate(doc)); + CollectionDockingView.Instance.AddRightSplit(docDelegate ? (makeCopy ? Doc.MakeCopy(docDelegate) : docDelegate) : Doc.MakeDelegate(doc)); } else { let contextView = DocumentManager.Instance.getDocumentView(contextDoc); if (contextView) { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 05eb5c38a..7f75a95f0 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -336,7 +336,7 @@ export namespace DragManager { x: e.x, y: e.y, data: dragData, - mods: e.ctrlKey ? "Control" : "" + mods: e.altKey ? "AltKey" : "" } }) ); diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 223921428..4d40d09b2 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -186,7 +186,6 @@ export class TooltipTextMenu { let node = this.view.state.selection.$from.nodeAfter; let link = node && node.marks.find(m => m.type.name === "link"); if (link) { - console.log("Link to : " + link.attrs.href); let href: string = link.attrs.href; if (href.indexOf(DocServer.prepend("/doc/")) === 0) { let docid = href.replace(DocServer.prepend("/doc/"), ""); diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 866da010a..51ad0aa49 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -244,7 +244,7 @@ export class Main extends React.Component { let logoutRef = React.createRef(); return [ - , + ,
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index d4f660b3f..001ce3095 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -205,11 +205,12 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.Document; - const protoDest = destDoc.proto; - const protoSrc = sourceDoc.proto; - if (de.mods === "Control") { + if (de.mods === "AltKey") { + const protoDest = destDoc.proto; + const protoSrc = sourceDoc.proto; let src = protoSrc ? protoSrc : sourceDoc; let dst = protoDest ? protoDest : destDoc; - dst.data = src; + dst.data = (src.data! as ObjectField)[Copy](); dst.nativeWidth = src.nativeWidth; dst.nativeHeight = src.nativeHeight; } else { - Doc.MakeLink(protoSrc ? protoSrc : sourceDoc, protoDest ? protoDest : destDoc); + Doc.MakeLink(sourceDoc, destDoc); de.data.droppedDocuments.push(destDoc); } e.stopPropagation(); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f30022508..bf98fb40b 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -111,9 +111,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.Document; - const protoDest = destDoc.proto; - const protoSrc = sourceDoc.proto; - Doc.MakeLink(protoSrc ? protoSrc : sourceDoc, protoDest ? protoDest : destDoc); + Doc.MakeLink(sourceDoc, destDoc); de.data.droppedDocuments.push(destDoc); e.stopPropagation(); } diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 611cb66b6..68b692aad 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -31,7 +31,7 @@ export class LinkBox extends React.Component { @undoBatch onViewButtonPressed = async (e: React.PointerEvent): Promise => { e.stopPropagation(); - DocumentManager.Instance.jumpToDocument(this.props.pairedDoc); + DocumentManager.Instance.jumpToDocument(this.props.pairedDoc, e.altKey); } onEditButtonPressed = (e: React.PointerEvent): void => { diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 11117122d..4cf798249 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -6,8 +6,7 @@ import { LinkEditor } from "./LinkEditor"; import './LinkMenu.scss'; import React = require("react"); import { Doc, DocListCast } from "../../../new_fields/Doc"; -import { Cast, FieldValue } from "../../../new_fields/Types"; -import { listSpec } from "../../../new_fields/Schema"; +import { Cast, FieldValue, StrCast } from "../../../new_fields/Types"; import { Id } from "../../../new_fields/RefField"; interface Props { @@ -24,7 +23,7 @@ export class LinkMenu extends React.Component { return links.map(link => { let doc = FieldValue(Cast(link[key], Doc)); if (doc) { - return this._editingLink = link)} type={type} />; + return this._editingLink = link)} type={type} />; } }); } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index c898f697b..ad3b880cd 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -216,6 +216,8 @@ export namespace Doc { } export function MakeLink(source: Doc, target: Doc) { + let protoSrc = source.proto ? source.proto : source; + let protoTarg = target.proto ? target.proto : target; UndoManager.RunInBatch(() => { let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: -1 }); //let linkDoc = new Doc; @@ -226,15 +228,15 @@ export namespace Doc { linkDoc.proto!.linkedTo = target; linkDoc.proto!.linkedFrom = source; - let linkedFrom = Cast(target.linkedFromDocs, listSpec(Doc)); + let linkedFrom = Cast(protoTarg.linkedFromDocs, listSpec(Doc)); if (!linkedFrom) { - target.linkedFromDocs = linkedFrom = new List(); + protoTarg.linkedFromDocs = linkedFrom = new List(); } linkedFrom.push(linkDoc); - let linkedTo = Cast(source.linkedToDocs, listSpec(Doc)); + let linkedTo = Cast(protoSrc.linkedToDocs, listSpec(Doc)); if (!linkedTo) { - source.linkedToDocs = linkedTo = new List(); + protoSrc.linkedToDocs = linkedTo = new List(); } linkedTo.push(linkDoc); return linkDoc; -- cgit v1.2.3-70-g09d2 From 2c8aaae6f026199e3675f5e7b4677724d5089ae7 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 17 May 2019 14:53:09 -0400 Subject: added something to follow links in current tab ? --- src/client/util/DocumentManager.ts | 33 +++++++++++++--------- .../views/collections/CollectionSchemaView.tsx | 7 ----- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- 3 files changed, 20 insertions(+), 22 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index c6962ad8d..d06af6dd5 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,11 +1,14 @@ import { computed, observable } from 'mobx'; import { DocumentView } from '../views/nodes/DocumentView'; -import { Doc, DocListCast } from '../../new_fields/Doc'; +import { Doc, DocListCast, Opt } from '../../new_fields/Doc'; import { FieldValue, Cast, NumCast, BoolCast } from '../../new_fields/Types'; import { listSpec } from '../../new_fields/Schema'; import { undoBatch } from './UndoManager'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { Id } from '../../new_fields/RefField'; +import { CollectionView } from '../views/collections/CollectionView'; +import { CollectionPDFView } from '../views/collections/CollectionPDFView'; +import { CollectionVideoView } from '../views/collections/CollectionVideoView'; export class DocumentManager { @@ -27,31 +30,33 @@ export class DocumentManager { // this.DocumentViews = new Array(); } - public getDocumentViewById(id: string): DocumentView | null { + public getDocumentViewById(id: string, preferredCollection?: CollectionView | CollectionPDFView | CollectionVideoView): DocumentView | null { let toReturn: DocumentView | null = null; + let passes = preferredCollection ? [preferredCollection, undefined] : [undefined]; - //gets document view that is in a freeform canvas collection - DocumentManager.Instance.DocumentViews.map(view => { - if (view.props.Document[Id] === id) { - toReturn = view; - return; - } - }); - if (!toReturn) { + for (let i = 0; i < passes.length; i++) { DocumentManager.Instance.DocumentViews.map(view => { - let doc = view.props.Document.proto; - if (doc && doc[Id] === id) { + if (view.props.Document[Id] === id && (!passes[i] || view.props.ContainingCollectionView === preferredCollection)) { toReturn = view; + return; } }); + if (!toReturn) { + DocumentManager.Instance.DocumentViews.map(view => { + let doc = view.props.Document.proto; + if (doc && doc[Id] === id && (!passes[i] || view.props.ContainingCollectionView === preferredCollection)) { + toReturn = view; + } + }); + } } return toReturn; } - public getDocumentView(toFind: Doc): DocumentView | null { - return this.getDocumentViewById(toFind[Id]); + public getDocumentView(toFind: Doc, preferredCollection?: CollectionView | CollectionPDFView | CollectionVideoView): DocumentView | null { + return this.getDocumentViewById(toFind[Id], preferredCollection); } public getDocumentViews(toFind: Doc): DocumentView[] { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 497dfde88..e2b90e26d 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -24,14 +24,7 @@ import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; import { Id } from "../../../new_fields/RefField"; -import { isUndefined } from "typescript-collections/dist/lib/util"; -import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { Gateway } from "../../northstar/manager/Gateway"; -import { DocServer } from "../../DocServer"; -import { ColumnAttributeModel } from "../../northstar/core/attribute/AttributeModel"; -import { HistogramOperation } from "../../northstar/operations/HistogramOperation"; -import { AggregateFunction } from "../../northstar/model/idea/idea"; -import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel"; import { Docs } from "../../documents/Documents"; import { ContextMenu } from "../ContextMenu"; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 001ce3095..00aa71656 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -187,7 +187,7 @@ export class CollectionFreeFormDocumentView extends DocComponent Date: Sat, 18 May 2019 15:25:42 -0400 Subject: Refactored some things to get Debug viewer working again --- src/client/util/History.ts | 4 +- src/client/views/Main.tsx | 280 +--------------- src/client/views/MainView.tsx | 274 ++++++++++++++++ src/client/views/PresentationView.tsx | 1 - .../views/collections/CollectionTreeView.tsx | 8 +- src/debug/Viewer.tsx | 364 +++++++++++---------- 6 files changed, 468 insertions(+), 463 deletions(-) create mode 100644 src/client/views/MainView.tsx (limited to 'src/client/util') diff --git a/src/client/util/History.ts b/src/client/util/History.ts index 92d2b2b44..545ea8629 100644 --- a/src/client/util/History.ts +++ b/src/client/util/History.ts @@ -1,7 +1,7 @@ import { Doc, Opt, Field } from "../../new_fields/Doc"; import { DocServer } from "../DocServer"; -import { Main } from "../views/Main"; import { RouteStore } from "../../server/RouteStore"; +import { MainView } from "../views/MainView"; export namespace HistoryUtil { export interface DocInitializerList { @@ -114,7 +114,7 @@ export namespace HistoryUtil { const field = await DocServer.GetRefField(url.docId); await Promise.all(Object.keys(url.initializers).map(id => initDoc(id, url.initializers[id]))); if (field instanceof Doc) { - Main.Instance.openWorkspace(field, true); + MainView.Instance.openWorkspace(field, true); } } diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 177047a9a..3d9750a85 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -1,281 +1,11 @@ -import { IconName, library } from '@fortawesome/fontawesome-svg-core'; -import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, configure, observable, runInAction, trace } from 'mobx'; -import { observer } from 'mobx-react'; -import "normalize.css"; -import * as React from 'react'; +import { MainView } from "./MainView"; +import { Docs } from "../documents/Documents"; +import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; import * as ReactDOM from 'react-dom'; -import Measure from 'react-measure'; -import * as request from 'request'; -import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; -import { RouteStore } from '../../server/RouteStore'; -import { emptyFunction, returnTrue, Utils, returnOne, returnZero } from '../../Utils'; -import { Docs } from '../documents/Documents'; -import { SetupDrag, DragManager } from '../util/DragManager'; -import { Transform } from '../util/Transform'; -import { UndoManager } from '../util/UndoManager'; -import { PresentationView } from './PresentationView'; -import { CollectionDockingView } from './collections/CollectionDockingView'; -import { ContextMenu } from './ContextMenu'; -import { DocumentDecorations } from './DocumentDecorations'; -import { InkingControl } from './InkingControl'; -import "./Main.scss"; -import { MainOverlayTextBox } from './MainOverlayTextBox'; -import { DocumentView } from './nodes/DocumentView'; -import { PreviewCursor } from './PreviewCursor'; -import { SearchBox } from './SearchBox'; -import { SelectionManager } from '../util/SelectionManager'; -import { FieldResult, Field, Doc, Opt } from '../../new_fields/Doc'; -import { Cast, FieldValue, StrCast } from '../../new_fields/Types'; -import { DocServer } from '../DocServer'; -import { listSpec } from '../../new_fields/Schema'; -import { Id } from '../../new_fields/RefField'; -import { HistoryUtil } from '../util/History'; - - -@observer -export class Main extends React.Component { - public static Instance: Main; - @observable private _workspacesShown: boolean = false; - @observable public pwidth: number = 0; - @observable public pheight: number = 0; - - @computed private get mainContainer(): Opt { - return FieldValue(Cast(CurrentUserUtils.UserDocument.activeWorkspace, Doc)); - } - private set mainContainer(doc: Opt) { - if (doc) { - if (!("presentationView" in doc)) { - doc.presentationView = new Doc(); - } - CurrentUserUtils.UserDocument.activeWorkspace = doc; - } - } - - constructor(props: Readonly<{}>) { - super(props); - Main.Instance = this; - // causes errors to be generated when modifying an observable outside of an action - configure({ enforceActions: "observed" }); - if (window.location.pathname !== RouteStore.home) { - let pathname = window.location.pathname.split("/"); - if (pathname.length > 1 && pathname[pathname.length - 2] === 'doc') { - CurrentUserUtils.MainDocId = pathname[pathname.length - 1]; - } - } - - library.add(faFont); - library.add(faImage); - library.add(faFilePdf); - library.add(faObjectGroup); - library.add(faTable); - library.add(faGlobeAsia); - library.add(faUndoAlt); - library.add(faRedoAlt); - library.add(faPenNib); - library.add(faFilm); - library.add(faMusic); - library.add(faTree); - this.initEventListeners(); - this.initAuthenticationRouters(); - } - - initEventListeners = () => { - // window.addEventListener("pointermove", (e) => this.reportLocation(e)) - window.addEventListener("drop", (e) => e.preventDefault(), false); // drop event handler - window.addEventListener("dragover", (e) => e.preventDefault(), false); // drag event handler - window.addEventListener("keydown", (e) => { - if (e.key === "Escape") { - DragManager.AbortDrag(); - SelectionManager.DeselectAll(); - } - }, false); // drag event handler - // click interactions for the context menu - document.addEventListener("pointerdown", action(function (e: PointerEvent) { - if (!ContextMenu.Instance.intersects(e.pageX, e.pageY)) { - ContextMenu.Instance.clearItems(); - } - }), true); - } - - initAuthenticationRouters = async () => { - // Load the user's active workspace, or create a new one if initial session after signup - if (!CurrentUserUtils.MainDocId) { - const doc = await Cast(CurrentUserUtils.UserDocument.activeWorkspace, Doc); - if (doc) { - this.openWorkspace(doc); - } else { - this.createNewWorkspace(); - } - } else { - DocServer.GetRefField(CurrentUserUtils.MainDocId).then(field => - field instanceof Doc ? this.openWorkspace(field) : - this.createNewWorkspace(CurrentUserUtils.MainDocId)); - } - } - - @action - createNewWorkspace = async (id?: string) => { - const list = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc)); - if (list) { - let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, title: `WS collection ${list.length + 1}` }); - var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(CurrentUserUtils.UserDocument, 150), CollectionDockingView.makeDocumentConfig(freeformDoc, 600)] }] }; - let mainDoc = Docs.DockDocument([CurrentUserUtils.UserDocument, freeformDoc], JSON.stringify(dockingLayout), { title: `Workspace ${list.length + 1}` }); - list.push(mainDoc); - // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) - setTimeout(() => { - this.openWorkspace(mainDoc); - let pendingDocument = Docs.SchemaDocument(["title"], [], { title: "New Mobile Uploads" }); - mainDoc.optionalRightCollection = pendingDocument; - }, 0); - } - } - - @action - openWorkspace = async (doc: Doc, fromHistory = false) => { - CurrentUserUtils.MainDocId = doc[Id]; - this.mainContainer = doc; - fromHistory || HistoryUtil.pushState({ type: "doc", docId: doc[Id], initializers: {} }); - const col = await Cast(CurrentUserUtils.UserDocument.optionalRightCollection, Doc); - // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) - setTimeout(async () => { - if (col) { - const l = Cast(col.data, listSpec(Doc)); - if (l && l.length > 0) { - CollectionDockingView.Instance.AddRightSplit(col); - } - } - }, 100); - } - @action - onResize = (r: any) => { - this.pwidth = r.offset.width; - this.pheight = r.offset.height; - } - getPWidth = () => { - return this.pwidth; - } - getPHeight = () => { - return this.pheight; - } - @computed - get mainContent() { - let mainCont = this.mainContainer; - let content = !mainCont ? (null) : - ; - const pres = mainCont ? FieldValue(Cast(mainCont.presentationView, Doc)) : undefined; - return - {({ measureRef }) => -
- {content} - {pres ? : null} -
- } -
; - } - - /* for the expandable add nodes menu. Not included with the miscbuttons because once it expands it expands the whole div with it, making canvas interactions limited. */ - nodesMenu() { - - let imgurl = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"; - let pdfurl = "http://www.adobe.com/support/products/enterprise/knowledgecenter/media/c27211_sample_explain.pdf"; - let weburl = "https://cs.brown.edu/courses/cs166/"; - let audiourl = "http://techslides.com/demos/samples/sample.mp3"; - let videourl = "http://techslides.com/demos/sample-videos/small.mp4"; - - let addTextNode = action(() => Docs.TextDocument({ borderRounding: -1, width: 200, height: 200, title: "a text note" })); - let addColNode = action(() => Docs.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" })); - let addSchemaNode = action(() => Docs.SchemaDocument(["title"], [], { width: 200, height: 200, title: "a schema collection" })); - let addTreeNode = action(() => Docs.TreeDocument([CurrentUserUtils.UserDocument], { width: 250, height: 400, title: "Library:" + CurrentUserUtils.email, dropAction: "alias" })); - // let addTreeNode = action(() => Docs.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", dropAction: "copy" })); - let addVideoNode = action(() => Docs.VideoDocument(videourl, { width: 200, title: "video node" })); - let addPDFNode = action(() => Docs.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" })); - let addImageNode = action(() => Docs.ImageDocument(imgurl, { width: 200, title: "an image of a cat" })); - let addWebNode = action(() => Docs.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" })); - let addAudioNode = action(() => Docs.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })); - - let btns: [React.RefObject, IconName, string, () => Doc][] = [ - [React.createRef(), "font", "Add Textbox", addTextNode], - [React.createRef(), "image", "Add Image", addImageNode], - [React.createRef(), "file-pdf", "Add PDF", addPDFNode], - [React.createRef(), "film", "Add Video", addVideoNode], - [React.createRef(), "music", "Add Audio", addAudioNode], - [React.createRef(), "globe-asia", "Add Web Clipping", addWebNode], - [React.createRef(), "object-group", "Add Collection", addColNode], - [React.createRef(), "tree", "Add Tree", addTreeNode], - [React.createRef(), "table", "Add Schema", addSchemaNode], - ]; - - return < div id="add-nodes-menu" > - - - -
-
    - {btns.map(btn => -
  • - -
  • )} -
-
-
; - } - - /* @TODO this should really be moved into a moveable toolbar component, but for now let's put it here to meet the deadline */ - @computed - get miscButtons() { - let logoutRef = React.createRef(); - - return [ - , -
- - - -
, -
, -
-
- ]; - - } - - render() { - return ( -
- - {this.mainContent} - - - {this.nodesMenu()} - {this.miscButtons} - - -
- ); - } -} +import * as React from 'react'; (async () => { await Docs.initProtos(); await CurrentUserUtils.loadCurrentUser(); - ReactDOM.render(
, document.getElementById('root')); + ReactDOM.render(, document.getElementById('root')); })(); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx new file mode 100644 index 000000000..d0d77bbf4 --- /dev/null +++ b/src/client/views/MainView.tsx @@ -0,0 +1,274 @@ +import { IconName, library } from '@fortawesome/fontawesome-svg-core'; +import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, configure, observable, runInAction, trace } from 'mobx'; +import { observer } from 'mobx-react'; +import "normalize.css"; +import * as React from 'react'; +import Measure from 'react-measure'; +import * as request from 'request'; +import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; +import { RouteStore } from '../../server/RouteStore'; +import { emptyFunction, returnTrue, Utils, returnOne, returnZero } from '../../Utils'; +import { Docs } from '../documents/Documents'; +import { SetupDrag, DragManager } from '../util/DragManager'; +import { Transform } from '../util/Transform'; +import { UndoManager } from '../util/UndoManager'; +import { PresentationView } from './PresentationView'; +import { CollectionDockingView } from './collections/CollectionDockingView'; +import { ContextMenu } from './ContextMenu'; +import { DocumentDecorations } from './DocumentDecorations'; +import { InkingControl } from './InkingControl'; +import "./Main.scss"; +import { MainOverlayTextBox } from './MainOverlayTextBox'; +import { DocumentView } from './nodes/DocumentView'; +import { PreviewCursor } from './PreviewCursor'; +import { SearchBox } from './SearchBox'; +import { SelectionManager } from '../util/SelectionManager'; +import { FieldResult, Field, Doc, Opt } from '../../new_fields/Doc'; +import { Cast, FieldValue, StrCast } from '../../new_fields/Types'; +import { DocServer } from '../DocServer'; +import { listSpec } from '../../new_fields/Schema'; +import { Id } from '../../new_fields/RefField'; +import { HistoryUtil } from '../util/History'; + + +@observer +export class MainView extends React.Component { + public static Instance: MainView; + @observable private _workspacesShown: boolean = false; + @observable public pwidth: number = 0; + @observable public pheight: number = 0; + + @computed private get mainContainer(): Opt { + return FieldValue(Cast(CurrentUserUtils.UserDocument.activeWorkspace, Doc)); + } + private set mainContainer(doc: Opt) { + if (doc) { + if (!("presentationView" in doc)) { + doc.presentationView = new Doc(); + } + CurrentUserUtils.UserDocument.activeWorkspace = doc; + } + } + + constructor(props: Readonly<{}>) { + super(props); + MainView.Instance = this; + // causes errors to be generated when modifying an observable outside of an action + configure({ enforceActions: "observed" }); + if (window.location.pathname !== RouteStore.home) { + let pathname = window.location.pathname.split("/"); + if (pathname.length > 1 && pathname[pathname.length - 2] === 'doc') { + CurrentUserUtils.MainDocId = pathname[pathname.length - 1]; + } + } + + library.add(faFont); + library.add(faImage); + library.add(faFilePdf); + library.add(faObjectGroup); + library.add(faTable); + library.add(faGlobeAsia); + library.add(faUndoAlt); + library.add(faRedoAlt); + library.add(faPenNib); + library.add(faFilm); + library.add(faMusic); + library.add(faTree); + this.initEventListeners(); + this.initAuthenticationRouters(); + } + + initEventListeners = () => { + // window.addEventListener("pointermove", (e) => this.reportLocation(e)) + window.addEventListener("drop", (e) => e.preventDefault(), false); // drop event handler + window.addEventListener("dragover", (e) => e.preventDefault(), false); // drag event handler + window.addEventListener("keydown", (e) => { + if (e.key === "Escape") { + DragManager.AbortDrag(); + SelectionManager.DeselectAll(); + } + }, false); // drag event handler + // click interactions for the context menu + document.addEventListener("pointerdown", action(function (e: PointerEvent) { + if (!ContextMenu.Instance.intersects(e.pageX, e.pageY)) { + ContextMenu.Instance.clearItems(); + } + }), true); + } + + initAuthenticationRouters = async () => { + // Load the user's active workspace, or create a new one if initial session after signup + if (!CurrentUserUtils.MainDocId) { + const doc = await Cast(CurrentUserUtils.UserDocument.activeWorkspace, Doc); + if (doc) { + this.openWorkspace(doc); + } else { + this.createNewWorkspace(); + } + } else { + DocServer.GetRefField(CurrentUserUtils.MainDocId).then(field => + field instanceof Doc ? this.openWorkspace(field) : + this.createNewWorkspace(CurrentUserUtils.MainDocId)); + } + } + + @action + createNewWorkspace = async (id?: string) => { + const list = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc)); + if (list) { + let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, title: `WS collection ${list.length + 1}` }); + var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(CurrentUserUtils.UserDocument, 150), CollectionDockingView.makeDocumentConfig(freeformDoc, 600)] }] }; + let mainDoc = Docs.DockDocument([CurrentUserUtils.UserDocument, freeformDoc], JSON.stringify(dockingLayout), { title: `Workspace ${list.length + 1}` }); + list.push(mainDoc); + // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) + setTimeout(() => { + this.openWorkspace(mainDoc); + let pendingDocument = Docs.SchemaDocument(["title"], [], { title: "New Mobile Uploads" }); + mainDoc.optionalRightCollection = pendingDocument; + }, 0); + } + } + + @action + openWorkspace = async (doc: Doc, fromHistory = false) => { + CurrentUserUtils.MainDocId = doc[Id]; + this.mainContainer = doc; + fromHistory || HistoryUtil.pushState({ type: "doc", docId: doc[Id], initializers: {} }); + const col = await Cast(CurrentUserUtils.UserDocument.optionalRightCollection, Doc); + // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) + setTimeout(async () => { + if (col) { + const l = Cast(col.data, listSpec(Doc)); + if (l && l.length > 0) { + CollectionDockingView.Instance.AddRightSplit(col); + } + } + }, 100); + } + @action + onResize = (r: any) => { + this.pwidth = r.offset.width; + this.pheight = r.offset.height; + } + getPWidth = () => { + return this.pwidth; + } + getPHeight = () => { + return this.pheight; + } + @computed + get mainContent() { + let mainCont = this.mainContainer; + let content = !mainCont ? (null) : + ; + const pres = mainCont ? FieldValue(Cast(mainCont.presentationView, Doc)) : undefined; + return + {({ measureRef }) => +
+ {content} + {pres ? : null} +
+ } +
; + } + + /* for the expandable add nodes menu. Not included with the miscbuttons because once it expands it expands the whole div with it, making canvas interactions limited. */ + nodesMenu() { + + let imgurl = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"; + let pdfurl = "http://www.adobe.com/support/products/enterprise/knowledgecenter/media/c27211_sample_explain.pdf"; + let weburl = "https://cs.brown.edu/courses/cs166/"; + let audiourl = "http://techslides.com/demos/samples/sample.mp3"; + let videourl = "http://techslides.com/demos/sample-videos/small.mp4"; + + let addTextNode = action(() => Docs.TextDocument({ borderRounding: -1, width: 200, height: 200, title: "a text note" })); + let addColNode = action(() => Docs.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" })); + let addSchemaNode = action(() => Docs.SchemaDocument(["title"], [], { width: 200, height: 200, title: "a schema collection" })); + let addTreeNode = action(() => Docs.TreeDocument([CurrentUserUtils.UserDocument], { width: 250, height: 400, title: "Library:" + CurrentUserUtils.email, dropAction: "alias" })); + // let addTreeNode = action(() => Docs.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", dropAction: "copy" })); + let addVideoNode = action(() => Docs.VideoDocument(videourl, { width: 200, title: "video node" })); + let addPDFNode = action(() => Docs.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" })); + let addImageNode = action(() => Docs.ImageDocument(imgurl, { width: 200, title: "an image of a cat" })); + let addWebNode = action(() => Docs.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" })); + let addAudioNode = action(() => Docs.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })); + + let btns: [React.RefObject, IconName, string, () => Doc][] = [ + [React.createRef(), "font", "Add Textbox", addTextNode], + [React.createRef(), "image", "Add Image", addImageNode], + [React.createRef(), "file-pdf", "Add PDF", addPDFNode], + [React.createRef(), "film", "Add Video", addVideoNode], + [React.createRef(), "music", "Add Audio", addAudioNode], + [React.createRef(), "globe-asia", "Add Web Clipping", addWebNode], + [React.createRef(), "object-group", "Add Collection", addColNode], + [React.createRef(), "tree", "Add Tree", addTreeNode], + [React.createRef(), "table", "Add Schema", addSchemaNode], + ]; + + return < div id="add-nodes-menu" > + + + +
+
    + {btns.map(btn => +
  • + +
  • )} +
+
+ ; + } + + /* @TODO this should really be moved into a moveable toolbar component, but for now let's put it here to meet the deadline */ + @computed + get miscButtons() { + let logoutRef = React.createRef(); + + return [ + , +
+ + + +
, +
, +
+
+ ]; + + } + + render() { + return ( +
+ + {this.mainContent} + + + {this.nodesMenu()} + {this.miscButtons} + + +
+ ); + } +} diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx index 7d0dc2913..9c37e9000 100644 --- a/src/client/views/PresentationView.tsx +++ b/src/client/views/PresentationView.tsx @@ -2,7 +2,6 @@ import { observer } from "mobx-react"; import React = require("react"); import { observable, action, runInAction, reaction } from "mobx"; import "./PresentationView.scss"; -import "./Main.tsx"; import { DocumentManager } from "../util/DocumentManager"; import { Utils } from "../../Utils"; import { Doc, DocListCast, DocListCastAsync } from "../../new_fields/Doc"; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 35a9f34cf..4cc4ae6b6 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -14,12 +14,12 @@ import { Doc, DocListCast } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/RefField'; import { ContextMenu } from '../ContextMenu'; import { undoBatch } from '../../util/UndoManager'; -import { Main } from '../Main'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; import { CollectionDockingView } from './CollectionDockingView'; import { DocumentManager } from '../../util/DocumentManager'; import { List } from '../../../new_fields/List'; import { Docs } from '../../documents/Documents'; +import { MainView } from '../MainView'; export interface TreeViewProps { @@ -52,7 +52,7 @@ class TreeView extends React.Component { @undoBatch openRight = async () => { if (this.props.document.dockingConfig) { - Main.Instance.openWorkspace(this.props.document); + MainView.Instance.openWorkspace(this.props.document); } else { CollectionDockingView.Instance.AddRightSplit(this.props.document); } @@ -140,7 +140,7 @@ class TreeView extends React.Component { onWorkspaceContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => Main.Instance.openWorkspace(this.props.document)) }); + ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.props.document)) }); ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.document) }); ContextMenu.Instance.addItem({ description: "Open Fields", event: () => CollectionDockingView.Instance.AddRightSplit(Docs.KVPDocument(this.props.document, @@ -215,7 +215,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { } onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "Create Workspace", event: undoBatch(() => Main.Instance.createNewWorkspace()) }); + ContextMenu.Instance.addItem({ description: "Create Workspace", event: undoBatch(() => MainView.Instance.createNewWorkspace()) }); } if (!ContextMenu.Instance.getItems().some(item => item.description === "Delete")) { ContextMenu.Instance.addItem({ description: "Delete", event: undoBatch(() => this.remove(this.props.Document)) }); diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index 4cac09dee..d9b07aac6 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -3,184 +3,186 @@ import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { observer } from 'mobx-react'; - -// configure({ -// enforceActions: "observed" -// }); - -// @observer -// class FieldViewer extends React.Component<{ field: BasicField }> { -// render() { -// return {JSON.stringify(this.props.field.Data)} ({this.props.field.Id}); -// } -// } - -// @observer -// class KeyViewer extends React.Component<{ field: Key }> { -// render() { -// return this.props.field.Name; -// } -// } - -// @observer -// class ListViewer extends React.Component<{ field: ListField }>{ -// @observable -// expanded = false; - -// render() { -// let content; -// if (this.expanded) { -// content = ( -//
-// {this.props.field.Data.map(field => )} -//
-// ); -// } else { -// content = <>[...] ({this.props.field.Id}); -// } -// return ( -//
-// -// {content} -//
-// ); -// } -// } - -// @observer -// class DocumentViewer extends React.Component<{ field: Document }> { -// private keyMap: ObservableMap = new ObservableMap; - -// private disposer?: Lambda; - -// componentDidMount() { -// let f = () => { -// Array.from(this.props.field._proxies.keys()).forEach(id => { -// if (!this.keyMap.has(id)) { -// Server.GetField(id, (field) => { -// if (field && field instanceof Key) { -// this.keyMap.set(id, field); -// } -// }); -// } -// }); -// }; -// this.disposer = this.props.field._proxies.observe(f); -// f(); -// } - -// componentWillUnmount() { -// if (this.disposer) { -// this.disposer(); -// } -// } - -// render() { -// let fields = Array.from(this.props.field._proxies.entries()).map(kv => { -// let key = this.keyMap.get(kv[0]); -// return ( -//
-// ({key ? key.Name : kv[0]}): -// -//
-// ); -// }); -// return ( -//
-// Document ({this.props.field.Id}) -//
-// {fields} -//
-//
-// ); -// } -// } - -// @observer -// class DebugViewer extends React.Component<{ fieldId: string }> { -// @observable -// private field?: Field; - -// @observable -// private error?: string; - -// constructor(props: { fieldId: string }) { -// super(props); -// this.update(); -// } - -// update() { -// Server.GetField(this.props.fieldId, action((field: Opt) => { -// this.field = field; -// if (!field) { -// this.error = `Field with id ${this.props.fieldId} not found`; -// } -// })); - -// } - -// render() { -// let content; -// if (this.field) { -// // content = this.field.ToJson(); -// if (this.field instanceof ListField) { -// content = (); -// } else if (this.field instanceof Document) { -// content = (); -// } else if (this.field instanceof BasicField) { -// content = (); -// } else if (this.field instanceof Key) { -// content = (); -// } else { -// content = (Unrecognized field type); -// } -// } else if (this.error) { -// content = Field {this.props.fieldId} not found ; -// } else { -// content = Field loading: {this.props.fieldId}; -// } -// return content; -// } -// } - -// @observer -// class Viewer extends React.Component { -// @observable -// private idToAdd: string = ''; - -// @observable -// private ids: string[] = []; - -// @action -// inputOnChange = (e: React.ChangeEvent) => { -// this.idToAdd = e.target.value; -// } - -// @action -// onKeyPress = (e: React.KeyboardEvent) => { -// if (e.key === "Enter") { -// this.ids.push(this.idToAdd); -// this.idToAdd = ""; -// } -// } - -// render() { -// return ( -// <> -// -//
-// {this.ids.map(id => )} -//
-// -// ); -// } -// } - -// ReactDOM.render(( -//
-// -//
), -// document.getElementById('root') -// ); \ No newline at end of file +import { CurrentUserUtils } from '../server/authentication/models/current_user_utils'; +import { RouteStore } from '../server/RouteStore'; +import { emptyFunction } from '../Utils'; +import { Docs } from '../client/documents/Documents'; +import { SetupDrag } from '../client/util/DragManager'; +import { Transform } from '../client/util/Transform'; +import { UndoManager } from '../client/util/UndoManager'; +import { PresentationView } from '../client/views/PresentationView'; +import { CollectionDockingView } from '../client/views/collections/CollectionDockingView'; +import { ContextMenu } from '../client/views/ContextMenu'; +import { DocumentDecorations } from '../client/views/DocumentDecorations'; +import { InkingControl } from '../client/views/InkingControl'; +import { MainOverlayTextBox } from '../client/views/MainOverlayTextBox'; +import { DocumentView } from '../client/views/nodes/DocumentView'; +import { PreviewCursor } from '../client/views/PreviewCursor'; +import { SearchBox } from '../client/views/SearchBox'; +import { SelectionManager } from '../client/util/SelectionManager'; +import { Doc, Field, FieldResult } from '../new_fields/Doc'; +import { Cast } from '../new_fields/Types'; +import { DocServer } from '../client/DocServer'; +import { listSpec } from '../new_fields/Schema'; +import { Id } from '../new_fields/RefField'; +import { HistoryUtil } from '../client/util/History'; +import { List } from '../new_fields/List'; +import { URLField } from '../new_fields/URLField'; + +CurrentUserUtils; +RouteStore; +emptyFunction; +Docs; +SetupDrag; +Transform; +UndoManager; +PresentationView; +CollectionDockingView; +ContextMenu; +DocumentDecorations; +InkingControl; +MainOverlayTextBox; +DocumentView; +PreviewCursor; +SearchBox; +SelectionManager; +Doc; +Cast; +DocServer; +listSpec; +Id; +HistoryUtil; + +configure({ + enforceActions: "observed" +}); + +@observer +class ListViewer extends React.Component<{ field: List }>{ + @observable + expanded = false; + + render() { + let content; + if (this.expanded) { + content = ( +
+ {this.props.field.map((field, index) => )} +
+ ); + } else { + content = <>[...]; + } + return ( +
+ + {content} +
+ ); + } +} + +@observer +class DocumentViewer extends React.Component<{ field: Doc }> { + @observable + expanded = false; + render() { + let content; + if (this.expanded) { + const keys = Object.keys(this.props.field); + let fields = keys.map(key => { + return ( +
+ ({key}): + +
+ ); + }); + content = ( +
+ Document ({this.props.field[Id]}) +
+ {fields} +
+
+ ); + } else { + content = <>[...] ({this.props.field[Id]}); + } + return ( +
+ + {content} +
+ ); + } +} + +@observer +class DebugViewer extends React.Component<{ field: FieldResult }> { + + render() { + let content; + const field = this.props.field; + if (field instanceof List) { + content = (); + } else if (field instanceof Doc) { + content = (); + } else if (typeof field === "string") { + content =

"{field}"

; + } else if (typeof field === "number" || typeof field === "boolean") { + content =

{field}

; + } else if (field instanceof URLField) { + content =

{field.url.href}

; + } else { + content =

Unrecognized field type

; + } + return content; + } +} + +@observer +class Viewer extends React.Component { + @observable + private idToAdd: string = ''; + + @observable + private fields: Field[] = []; + + @action + inputOnChange = (e: React.ChangeEvent) => { + this.idToAdd = e.target.value; + } + + @action + onKeyPress = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + DocServer.GetRefField(this.idToAdd).then(action((field: any) => { + if (field !== undefined) { + this.fields.push(field); + } + })); + this.idToAdd = ""; + } + } + + render() { + return ( + <> + +
+ {this.fields.map((field, index) => )} +
+ + ); + } +} + +ReactDOM.render(( +
+ +
), + document.getElementById('root') +); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From b789ac4cc3fe013139825f811d7574e1d305c2cc Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sun, 19 May 2019 20:30:50 -0400 Subject: Added link follow behavior --- src/client/util/DocumentManager.ts | 7 ++++--- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index d06af6dd5..be448098a 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -115,7 +115,7 @@ export class DocumentManager { } @undoBatch - public jumpToDocument = async (docDelegate: Doc, makeCopy: boolean = true): Promise => { + public jumpToDocument = async (docDelegate: Doc, makeCopy: boolean = true, dockFunc?: (doc: Doc) => void): Promise => { let doc = docDelegate.proto ? docDelegate.proto : docDelegate; const page = NumCast(doc.page, undefined); const contextDoc = await Cast(doc.annotationOn, Doc); @@ -128,14 +128,15 @@ export class DocumentManager { docView.props.focus(docView.props.Document); } else { if (!contextDoc) { - CollectionDockingView.Instance.AddRightSplit(docDelegate ? (makeCopy ? Doc.MakeCopy(docDelegate) : docDelegate) : Doc.MakeDelegate(doc)); + const actualDoc = docDelegate ? (makeCopy ? Doc.MakeCopy(docDelegate) : docDelegate) : Doc.MakeDelegate(doc); + (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc); } else { let contextView = DocumentManager.Instance.getDocumentView(contextDoc); if (contextView) { contextDoc.panTransformType = "Ease"; contextView.props.focus(contextDoc); } else { - CollectionDockingView.Instance.AddRightSplit(contextDoc); + (dockFunc || CollectionDockingView.Instance.AddRightSplit)(contextDoc); } } } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index fa44ec9f3..5bff08280 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -239,7 +239,8 @@ export class CollectionFreeFormDocumentView extends DocComponent this.props.addDocTab(document, maxLocation)); } } } -- cgit v1.2.3-70-g09d2 From af2346983eae1145167b70faf96a9aec0ca82427 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Mon, 20 May 2019 00:09:47 -0400 Subject: Fixed a bunch of demo bugs Moved Field Symbols to separate file Editing is mostly working in debug viewer --- deploy/debug/viewer.html | 1 + src/client/DocServer.ts | 3 +- src/client/northstar/dash-fields/HistogramField.ts | 7 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 2 +- src/client/util/DocumentManager.ts | 2 +- src/client/util/SearchUtil.ts | 2 +- src/client/util/TooltipTextMenu.tsx | 2 +- src/client/util/type_decls.d | 128 +++++++-------------- src/client/views/EditableView.tsx | 10 +- src/client/views/MainView.tsx | 2 +- src/client/views/PresentationView.tsx | 2 +- src/client/views/SearchBox.tsx | 2 +- .../views/collections/CollectionBaseView.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 14 ++- src/client/views/collections/CollectionPDFView.tsx | 2 +- .../views/collections/CollectionSchemaView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 2 +- .../views/collections/CollectionVideoView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../views/collections/ParentDocumentSelector.tsx | 2 +- .../CollectionFreeFormLinksView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 3 - src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/KeyValueBox.tsx | 4 +- src/client/views/nodes/KeyValuePair.tsx | 4 +- src/client/views/nodes/LinkMenu.tsx | 2 +- src/debug/Viewer.tsx | 53 +++++++-- src/new_fields/CursorField.ts | 7 +- src/new_fields/DateField.ts | 7 +- src/new_fields/Doc.ts | 43 ++++--- src/new_fields/FieldSymbols.ts | 10 ++ src/new_fields/HtmlField.ts | 7 +- src/new_fields/IconField.ts | 7 +- src/new_fields/InkField.ts | 7 +- src/new_fields/List.ts | 16 ++- src/new_fields/ObjectField.ts | 7 +- src/new_fields/Proxy.ts | 9 +- src/new_fields/RefField.ts | 5 +- src/new_fields/RichTextField.ts | 7 +- src/new_fields/URLField.ts | 9 +- src/new_fields/util.ts | 7 +- 42 files changed, 240 insertions(+), 173 deletions(-) create mode 100644 src/new_fields/FieldSymbols.ts (limited to 'src/client/util') diff --git a/deploy/debug/viewer.html b/deploy/debug/viewer.html index 3785a6602..8c265ccb8 100644 --- a/deploy/debug/viewer.html +++ b/deploy/debug/viewer.html @@ -3,6 +3,7 @@ Document Debugger + diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index f1b50d5a0..cbcf751ee 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -3,7 +3,8 @@ import { MessageStore } from "./../server/Message"; import { Opt } from '../new_fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; -import { RefField, HandleUpdate, Id } from '../new_fields/RefField'; +import { RefField } from '../new_fields/RefField'; +import { Id, HandleUpdate } from '../new_fields/FieldSymbols'; export namespace DocServer { const _cache: { [id: string]: RefField | Promise> } = {}; diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 1ee2189b9..31040a474 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -3,10 +3,11 @@ import { custom, serializable } from "serializr"; import { ColumnAttributeModel } from "../../../client/northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel"; import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation"; -import { ObjectField, Copy } from "../../../new_fields/ObjectField"; +import { ObjectField } from "../../../new_fields/ObjectField"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { OmitKeys } from "../../../Utils"; import { Deserializable } from "../../util/SerializationHelper"; +import { Copy, ToScriptString } from "../../../new_fields/FieldSymbols"; function serialize(field: HistogramField) { let obj = OmitKeys(field, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit; @@ -55,4 +56,8 @@ export class HistogramField extends ObjectField { let z = this.HistoOp.Copy; return new HistogramField(HistogramOperation.Duplicate(this.HistoOp)); } + + [ToScriptString]() { + return "invalid"; + } } \ No newline at end of file diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index eb1ad69b7..a9646ed31 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -19,7 +19,7 @@ import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives"; import { StyleConstants } from "../utils/StyleContants"; import { Cast } from "../../../new_fields/Types"; import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/RefField"; +import { Id } from "../../../new_fields/FieldSymbols"; @observer diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index be448098a..a5e768dcf 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -5,10 +5,10 @@ import { FieldValue, Cast, NumCast, BoolCast } from '../../new_fields/Types'; import { listSpec } from '../../new_fields/Schema'; import { undoBatch } from './UndoManager'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; -import { Id } from '../../new_fields/RefField'; import { CollectionView } from '../views/collections/CollectionView'; import { CollectionPDFView } from '../views/collections/CollectionPDFView'; import { CollectionVideoView } from '../views/collections/CollectionVideoView'; +import { Id } from '../../new_fields/FieldSymbols'; export class DocumentManager { diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 4ccff0d1b..e8eb70837 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -1,7 +1,7 @@ import * as rp from 'request-promise'; import { DocServer } from '../DocServer'; import { Doc } from '../../new_fields/Doc'; -import { Id } from '../../new_fields/RefField'; +import { Id } from '../../new_fields/FieldSymbols'; export namespace SearchUtil { export function Search(query: string, returnDocs: true): Promise; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 4d40d09b2..a1f80120f 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 { Id } from "../../new_fields/RefField"; 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"; const SVG = "http://www.w3.org/2000/svg"; diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d index 47c3481b2..51114d0e2 100644 --- a/src/client/util/type_decls.d +++ b/src/client/util/type_decls.d @@ -119,104 +119,54 @@ interface URL { username: string; toJSON(): string; } +interface PromiseLike { + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): PromiseLike; +} +interface Promise { + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; +} -declare type FieldId = string; +declare const Update: unique symbol; +declare const Self: unique symbol; +declare const SelfProxy: unique symbol; +declare const HandleUpdate: unique symbol; +declare const Id: unique symbol; +declare const OnUpdate: unique symbol; +declare const Parent: unique symbol; +declare const Copy: unique symbol; +declare const ToScriptString: unique symbol; -declare abstract class Field { - Id: FieldId; - abstract ToScriptString(): string; - abstract TrySetValue(value: any): boolean; - abstract GetValue(): any; - abstract Copy(): Field; -} +declare abstract class RefField { + readonly [Id]: FieldId; + + constructor(id?: FieldId); + protected [HandleUpdate]?(diff: any): void; -declare abstract class BasicField extends Field { - constructor(data: T); - Data: T; - TrySetValue(value: any): boolean; - GetValue(): any; + abstract [ToScriptString](): string; } -declare class TextField extends BasicField{ - constructor(); - constructor(data: string); - ToScriptString(): string; - Copy(): Field; -} -declare class ImageField extends BasicField{ - constructor(); - constructor(data: URL); - ToScriptString(): string; - Copy(): Field; -} -declare class HtmlField extends BasicField{ - constructor(); - constructor(data: string); - ToScriptString(): string; - Copy(): Field; -} -declare class NumberField extends BasicField{ - constructor(); - constructor(data: number); - ToScriptString(): string; - Copy(): Field; -} -declare class WebField extends BasicField{ - constructor(); - constructor(data: URL); - ToScriptString(): string; - Copy(): Field; -} -declare class ListField extends BasicField{ - constructor(); - constructor(data: T[]); - ToScriptString(): string; - Copy(): Field; -} -declare class Key extends Field { - constructor(name:string); - Name: string; - TrySetValue(value: any): boolean; - GetValue(): any; - Copy(): Field; - ToScriptString(): string; -} -declare type FIELD_WAITING = null; -declare type Opt = T | undefined; -declare type FieldValue = Opt | FIELD_WAITING; -// @ts-ignore -declare class Document extends Field { - TrySetValue(value: any): boolean; - GetValue(): any; - Copy(): Field; - ToScriptString(): string; +declare abstract class ObjectField { + protected [OnUpdate](diff?: any): void; + private [Parent]?: RefField | ObjectField; + abstract [Copy](): ObjectField; - Width(): number; - Height(): number; - Scale(): number; - Title: string; + abstract [ToScriptString](): string; +} +declare type FieldId = string; - Get(key: Key): FieldValue; - GetAsync(key: Key, callback: (field: Field) => void): boolean; - GetOrCreateAsync(key: Key, ctor: { new(): T }, callback: (field: T) => void): void; - GetT(key: Key, ctor: { new(): T }): FieldValue; - GetOrCreate(key: Key, ctor: { new(): T }): T; - GetData(key: Key, ctor: { new(): U }, defaultVal: T): T; - GetHtml(key: Key, defaultVal: string): string; - GetNumber(key: Key, defaultVal: number): number; - GetText(key: Key, defaultVal: string): string; - GetList(key: Key, defaultVal: T[]): T[]; - Set(key: Key, field: Field | undefined): void; - SetData(key: Key, value: T, ctor: { new(): U }): void; - SetText(key: Key, value: string): void; - SetNumber(key: Key, value: number): void; - GetPrototype(): FieldValue; - GetAllPrototypes(): Document[]; - MakeDelegate(): Document; +declare type Field = number | string | boolean | ObjectField | RefField; + +declare type Opt = T | undefined; +declare class Doc extends RefField { + [key: string]: Field | undefined; + [ToScriptString](): string; } -declare const KeyStore: { - [name: string]: Key; +declare class ListImpl extends ObjectField { + [index: number]: T | (T extends RefField ? Promise : never); + [ToScriptString](): string; + [Copy](): ObjectField; } // @ts-ignore diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 78143ccda..c946d68e1 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -22,7 +22,7 @@ export interface EditableProps { * The contents to render when not editing */ contents: any; - height: number; + height?: number; display?: string; oneLine?: boolean; } @@ -53,6 +53,12 @@ export class EditableView extends React.Component { } } + @action + onClick = (e: React.MouseEvent) => { + this.editing = true; + e.stopPropagation(); + } + render() { if (this.editing) { return this.editing = false)} @@ -60,7 +66,7 @@ export class EditableView extends React.Component { } else { return (
this.editing = true)} > + onClick={this.onClick} > {this.props.contents}
); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 400562f12..9edbba997 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -29,7 +29,7 @@ import { FieldResult, Field, Doc, Opt } from '../../new_fields/Doc'; import { Cast, FieldValue, StrCast } from '../../new_fields/Types'; import { DocServer } from '../DocServer'; import { listSpec } from '../../new_fields/Schema'; -import { Id } from '../../new_fields/RefField'; +import { Id } from '../../new_fields/FieldSymbols'; import { HistoryUtil } from '../util/History'; import { CollectionBaseView } from './collections/CollectionBaseView'; diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx index 9c37e9000..ce679aa0a 100644 --- a/src/client/views/PresentationView.tsx +++ b/src/client/views/PresentationView.tsx @@ -7,7 +7,7 @@ import { Utils } from "../../Utils"; import { Doc, DocListCast, DocListCastAsync } from "../../new_fields/Doc"; import { listSpec } from "../../new_fields/Schema"; import { Cast, NumCast, FieldValue, PromiseValue, StrCast } from "../../new_fields/Types"; -import { Id } from "../../new_fields/RefField"; +import { Id } from "../../new_fields/FieldSymbols"; import { List } from "../../new_fields/List"; import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 6e64e1af1..8efd8d266 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -16,7 +16,7 @@ import { isString } from 'util'; import { constant } from 'async'; import { DocServer } from '../DocServer'; import { Doc } from '../../new_fields/Doc'; -import { Id } from '../../new_fields/RefField'; +import { Id } from '../../new_fields/FieldSymbols'; import { DocumentManager } from '../util/DocumentManager'; import { SetupDrag } from '../util/DragManager'; import { Docs } from '../documents/Documents'; diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 84ffbac36..5686ccfef 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -7,8 +7,8 @@ import { Cast, FieldValue, PromiseValue, NumCast } from '../../../new_fields/Typ import { Doc, FieldResult, Opt, DocListCast } from '../../../new_fields/Doc'; import { listSpec } from '../../../new_fields/Schema'; import { List } from '../../../new_fields/List'; -import { Id } from '../../../new_fields/RefField'; import { SelectionManager } from '../../util/SelectionManager'; +import { Id } from '../../../new_fields/FieldSymbols'; export enum CollectionViewType { Invalid, diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 483209f86..e904358a9 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -6,7 +6,7 @@ import * as ReactDOM from 'react-dom'; import Measure from "react-measure"; import * as GoldenLayout from "../../../client/goldenLayout"; import { Doc, Field, Opt, DocListCast } from "../../../new_fields/Doc"; -import { FieldId, Id } from "../../../new_fields/RefField"; +import { FieldId } from "../../../new_fields/RefField"; import { listSpec } from "../../../new_fields/Schema"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { emptyFunction, returnTrue, Utils } from "../../../Utils"; @@ -21,6 +21,7 @@ import React = require("react"); import { ParentDocSelector } from './ParentDocumentSelector'; import { DocumentManager } from '../../util/DocumentManager'; import { CollectionViewType } from './CollectionBaseView'; +import { Id } from '../../../new_fields/FieldSymbols'; @observer export class CollectionDockingView extends React.Component { @@ -75,7 +76,7 @@ export class CollectionDockingView extends React.Component { let retVal = false; if (this._goldenLayout.root.contentItems[0].isRow) { retVal = Array.from(this._goldenLayout.root.contentItems[0].contentItems).some((child: any) => { @@ -118,7 +119,7 @@ export class CollectionDockingView extends React.Component { let docs = Cast(this.props.Document.data, listSpec(Doc)); if (docs) { docs.push(document); @@ -155,7 +156,7 @@ export class CollectionDockingView extends React.Component { let docs = Cast(this.props.Document.data, listSpec(Doc)); if (docs) { docs.push(document); @@ -412,10 +413,11 @@ export class DockedFrameRenderer extends React.Component { @observable private _panelWidth = 0; @observable private _panelHeight = 0; @observable private _document: Opt; - _stack: any; + get _stack(): any { + return (this.props as any).glContainer.parent.parent; + } constructor(props: any) { super(props); - this._stack = (this.props as any).glContainer.parent.parent; DocServer.GetRefField(this.props.documentId).then(action((f: Opt) => this._document = f as Doc)); } diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index a6614da21..5e51437a4 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -8,7 +8,7 @@ import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { CollectionRenderProps, CollectionBaseView, CollectionViewType } from "./CollectionBaseView"; import { emptyFunction } from "../../../Utils"; import { NumCast } from "../../../new_fields/Types"; -import { Id } from "../../../new_fields/RefField"; +import { Id } from "../../../new_fields/FieldSymbols"; @observer diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index f15da41ff..b25b48339 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -23,7 +23,7 @@ import { Opt, Field, Doc, DocListCastAsync, DocListCast } from "../../../new_fie import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; -import { Id } from "../../../new_fields/RefField"; +import { Id } from "../../../new_fields/FieldSymbols"; import { Gateway } from "../../northstar/manager/Gateway"; import { Docs } from "../../documents/Documents"; import { ContextMenu } from "../ContextMenu"; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 72fa69cb1..8ad495762 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -11,7 +11,7 @@ import React = require("react"); import { Document, listSpec } from '../../../new_fields/Schema'; import { Cast, StrCast, BoolCast, FieldValue } from '../../../new_fields/Types'; import { Doc, DocListCast } from '../../../new_fields/Doc'; -import { Id } from '../../../new_fields/RefField'; +import { Id } from '../../../new_fields/FieldSymbols'; import { ContextMenu } from '../ContextMenu'; import { undoBatch } from '../../util/UndoManager'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 9ab959f3c..27f23a1a8 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -7,7 +7,7 @@ import "./CollectionVideoView.scss"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { emptyFunction } from "../../../Utils"; -import { Id } from "../../../new_fields/RefField"; +import { Id } from "../../../new_fields/FieldSymbols"; import { VideoBox } from "../nodes/VideoBox"; import { NumCast } from "../../../new_fields/Types"; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 59c763be8..bfdef8e8c 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -2,7 +2,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faProjectDiagram, faSquare, faTh, faTree, faSignature, faThList } from '@fortawesome/free-solid-svg-icons'; import { observer } from "mobx-react"; import * as React from 'react'; -import { Id } from '../../../new_fields/RefField'; +import { Id } from '../../../new_fields/FieldSymbols'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../ContextMenu"; diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 52f7914f3..4d07c31a7 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -3,7 +3,7 @@ import './ParentDocumentSelector.scss'; import { Doc } from "../../../new_fields/Doc"; import { observer } from "mobx-react"; import { observable, action, runInAction } from "mobx"; -import { Id } from "../../../new_fields/RefField"; +import { Id } from "../../../new_fields/FieldSymbols"; import { SearchUtil } from "../../util/SearchUtil"; import { CollectionDockingView } from "./CollectionDockingView"; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index d5ce4e1e7..e1ff715d1 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -11,7 +11,7 @@ import { Doc, DocListCastAsync, DocListCast } from "../../../../new_fields/Doc"; import { Cast, FieldValue, NumCast, StrCast } from "../../../../new_fields/Types"; import { listSpec } from "../../../../new_fields/Schema"; import { List } from "../../../../new_fields/List"; -import { Id } from "../../../../new_fields/RefField"; +import { Id } from "../../../../new_fields/FieldSymbols"; @observer export class CollectionFreeFormLinksView extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9cb8443f4..ee6f4821f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -22,9 +22,9 @@ import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Sc import { Doc, WidthSym, HeightSym } from "../../../../new_fields/Doc"; import { FieldValue, Cast, NumCast, BoolCast } from "../../../../new_fields/Types"; import { pageSchema } from "../../nodes/ImageBox"; -import { Id } from "../../../../new_fields/RefField"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { HistoryUtil } from "../../../util/History"; +import { Id } from "../../../../new_fields/FieldSymbols"; export const panZoomSchema = createSchema({ panX: "number", diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 4587c2227..2029b91e5 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -17,9 +17,6 @@ import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { List } from "../../../../new_fields/List"; import { ImageField } from "../../../../new_fields/URLField"; import { Template, Templates } from "../../Templates"; -import { Gateway } from "../../../northstar/manager/Gateway"; -import { DocServer } from "../../../DocServer"; -import { Id } from "../../../../new_fields/RefField"; interface MarqueeViewProps { getContainerTransform: () => Transform; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5f218fd1f..87c88f57c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -4,8 +4,7 @@ import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; -import { Copy, ObjectField } from "../../../new_fields/ObjectField"; -import { Id } from "../../../new_fields/RefField"; +import { ObjectField } from "../../../new_fields/ObjectField"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; import { BoolCast, Cast, FieldValue, StrCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; @@ -29,6 +28,7 @@ import { Template } from "./../Templates"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); +import { Id, Copy } from '../../../new_fields/FieldSymbols'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? library.add(faTrash); diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 86437a6c1..8cb576786 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -8,7 +8,7 @@ import "./KeyValueBox.scss"; import { KeyValuePair } from "./KeyValuePair"; import React = require("react"); import { NumCast, Cast, FieldValue } from "../../../new_fields/Types"; -import { Doc, IsField } from "../../../new_fields/Doc"; +import { Doc, Field } from "../../../new_fields/Doc"; @observer export class KeyValueBox extends React.Component { @@ -41,7 +41,7 @@ export class KeyValueBox extends React.Component { let res = script.run(); if (!res.success) return; const field = res.result; - if (IsField(field)) { + if (Field.IsField(field)) { realDoc[this._keyInput] = field; } this._keyInput = ""; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 4f7919f50..7a88985c0 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -9,7 +9,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import "./KeyValueBox.scss"; import "./KeyValuePair.scss"; import React = require("react"); -import { Doc, Opt, IsField } from '../../../new_fields/Doc'; +import { Doc, Opt, Field } from '../../../new_fields/Doc'; import { FieldValue } from '../../../new_fields/Types'; // Represents one row in a key value plane @@ -75,7 +75,7 @@ export class KeyValuePair extends React.Component { let res = script.run(); if (!res.success) return false; const field = res.result; - if (IsField(field)) { + if (Field.IsField(field)) { props.Document[props.fieldKey] = field; return true; } diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 4cf798249..3f09d6214 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -7,7 +7,7 @@ import './LinkMenu.scss'; import React = require("react"); import { Doc, DocListCast } from "../../../new_fields/Doc"; import { Cast, FieldValue, StrCast } from "../../../new_fields/Types"; -import { Id } from "../../../new_fields/RefField"; +import { Id } from "../../../new_fields/FieldSymbols"; interface Props { docView: DocumentView; diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index 720e1640a..4314e2132 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -3,11 +3,27 @@ import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { observer } from 'mobx-react'; -import { Doc, Field, FieldResult } from '../new_fields/Doc'; +import { Doc, Field, FieldResult, Opt } from '../new_fields/Doc'; import { DocServer } from '../client/DocServer'; -import { Id } from '../new_fields/RefField'; +import { Id } from '../new_fields/FieldSymbols'; import { List } from '../new_fields/List'; import { URLField } from '../new_fields/URLField'; +import { EditableView } from '../client/views/EditableView'; +import { CompileScript } from '../client/util/Scripting'; + +function applyToDoc(doc: { [index: string]: FieldResult }, key: string, scriptString: string): boolean; +function applyToDoc(doc: { [index: number]: FieldResult }, key: number, scriptString: string): boolean; +function applyToDoc(doc: any, key: string | number, scriptString: string): boolean { + let script = CompileScript(scriptString, { addReturn: true, params: { this: doc instanceof Doc ? Doc.name : List.name } }); + if (!script.compiled) { + return false; + } + const res = script.run({ this: doc }); + if (!res.success) return false; + if (!Field.IsField(res.result)) return false; + doc[key] = res.result; + return true; +} configure({ enforceActions: "observed" @@ -18,12 +34,18 @@ class ListViewer extends React.Component<{ field: List }>{ @observable expanded = false; + @action + onClick = (e: React.MouseEvent) => { + this.expanded = !this.expanded; + e.stopPropagation(); + } + render() { let content; if (this.expanded) { content = (
- {this.props.field.map((field, index) => )} + {this.props.field.map((field, index) => applyToDoc(this.props.field, index, value)} />)}
); } else { @@ -31,7 +53,7 @@ class ListViewer extends React.Component<{ field: List }>{ } return (
- + {content}
); @@ -42,6 +64,13 @@ class ListViewer extends React.Component<{ field: List }>{ class DocumentViewer extends React.Component<{ field: Doc }> { @observable expanded = false; + + @action + onClick = (e: React.MouseEvent) => { + this.expanded = !this.expanded; + e.stopPropagation(); + } + render() { let content; if (this.expanded) { @@ -50,7 +79,7 @@ class DocumentViewer extends React.Component<{ field: Doc }> { return (
({key}): - + applyToDoc(this.props.field, key, value)}>
); }); @@ -67,7 +96,7 @@ class DocumentViewer extends React.Component<{ field: Doc }> { } return (
- + {content}
); @@ -75,7 +104,7 @@ class DocumentViewer extends React.Component<{ field: Doc }> { } @observer -class DebugViewer extends React.Component<{ field: FieldResult }> { +class DebugViewer extends React.Component<{ field: FieldResult, setValue(value: string): boolean }> { render() { let content; @@ -90,10 +119,14 @@ class DebugViewer extends React.Component<{ field: FieldResult }> { content =

{field}

; } else if (field instanceof URLField) { content =

{field.url.href}

; + } else if (field instanceof Promise) { + return

Field loading

; } else { - content =

Unrecognized field type

; + return

Unrecognized field type

; } - return content; + + return Field.toScriptString(field)} SetValue={this.props.setValue} + contents={content}>; } } @@ -129,7 +162,7 @@ class Viewer extends React.Component { onChange={this.inputOnChange} onKeyDown={this.onKeyPress} />
- {this.fields.map((field, index) => )} + {this.fields.map((field, index) => false}>)}
); diff --git a/src/new_fields/CursorField.ts b/src/new_fields/CursorField.ts index fc144222c..1be1ec3e0 100644 --- a/src/new_fields/CursorField.ts +++ b/src/new_fields/CursorField.ts @@ -1,7 +1,8 @@ -import { ObjectField, Copy, OnUpdate } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; import { observable } from "mobx"; import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, createSimpleSchema, object } from "serializr"; +import { OnUpdate, ToScriptString, Copy } from "./FieldSymbols"; export type CursorPosition = { x: number, @@ -52,4 +53,8 @@ export default class CursorField extends ObjectField { [Copy]() { return new CursorField(this.data); } + + [ToScriptString]() { + return "invalid"; + } } \ No newline at end of file diff --git a/src/new_fields/DateField.ts b/src/new_fields/DateField.ts index c0a79f267..fc8abb9d9 100644 --- a/src/new_fields/DateField.ts +++ b/src/new_fields/DateField.ts @@ -1,6 +1,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, date } from "serializr"; -import { ObjectField, Copy } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString } from "./FieldSymbols"; @Deserializable("date") export class DateField extends ObjectField { @@ -15,4 +16,8 @@ export class DateField extends ObjectField { [Copy]() { return new DateField(this.date); } + + [ToScriptString]() { + return `new DateField(new Date(${this.date.toISOString()}))`; + } } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 02dd34cb4..f4514c33e 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -5,27 +5,33 @@ import { DocServer } from "../client/DocServer"; import { setter, getter, getField, updateFunction, deleteProperty } from "./util"; import { Cast, ToConstructor, PromiseValue, FieldValue, NumCast } from "./Types"; import { listSpec } from "./Schema"; -import { ObjectField, Parent, OnUpdate } from "./ObjectField"; -import { RefField, FieldId, Id, HandleUpdate } from "./RefField"; - -export function IsField(field: any): field is Field { - return (typeof field === "string") - || (typeof field === "number") - || (typeof field === "boolean") - || (field instanceof ObjectField) - || (field instanceof RefField); +import { ObjectField } from "./ObjectField"; +import { RefField, FieldId } from "./RefField"; +import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id } from "./FieldSymbols"; + +export namespace Field { + export function toScriptString(field: Field): string { + if (typeof field === "string") { + return `"${field}"`; + } else if (typeof field === "number" || typeof field === "boolean") { + return String(field); + } else { + return field[ToScriptString](); + } + } + export function IsField(field: any): field is Field { + return (typeof field === "string") + || (typeof field === "number") + || (typeof field === "boolean") + || (field instanceof ObjectField) + || (field instanceof RefField); + } } export type Field = number | string | boolean | ObjectField | RefField; export type Opt = T | undefined; export type FieldWaiting = T extends undefined ? never : Promise; export type FieldResult = Opt | FieldWaiting>; -export const Update = Symbol("Update"); -export const Self = Symbol("Self"); -export const SelfProxy = Symbol("SelfProxy"); -export const WidthSym = Symbol("Width"); -export const HeightSym = Symbol("Height"); - /** * Cast any field to either a List of Docs or undefined if the given field isn't a List of Docs. * If a default value is given, that will be returned instead of undefined. @@ -43,6 +49,9 @@ export function DocListCast(field: FieldResult): Doc[] { return Cast(field, listSpec(Doc), []).filter(d => d instanceof Doc) as Doc[]; } +export const WidthSym = Symbol("Width"); +export const HeightSym = Symbol("Height"); + @Deserializable("doc").withFields(["id"]) export class Doc extends RefField { constructor(id?: FieldId, forceSave?: boolean) { @@ -102,6 +111,10 @@ export class Doc extends RefField { public [WidthSym] = () => NumCast(this[SelfProxy].width); // bcz: is this the right way to access width/height? it didn't work with : this.width public [HeightSym] = () => NumCast(this[SelfProxy].height); + [ToScriptString]() { + return "invalid"; + } + public [HandleUpdate](diff: any) { console.log(diff); const set = diff.$set; diff --git a/src/new_fields/FieldSymbols.ts b/src/new_fields/FieldSymbols.ts new file mode 100644 index 000000000..a436dcf2b --- /dev/null +++ b/src/new_fields/FieldSymbols.ts @@ -0,0 +1,10 @@ + +export const Update = Symbol("Update"); +export const Self = Symbol("Self"); +export const SelfProxy = Symbol("SelfProxy"); +export const HandleUpdate = Symbol("HandleUpdate"); +export const Id = Symbol("Id"); +export const OnUpdate = Symbol("OnUpdate"); +export const Parent = Symbol("Parent"); +export const Copy = Symbol("Copy"); +export const ToScriptString = Symbol("Copy"); \ No newline at end of file diff --git a/src/new_fields/HtmlField.ts b/src/new_fields/HtmlField.ts index d998746bb..f952acff9 100644 --- a/src/new_fields/HtmlField.ts +++ b/src/new_fields/HtmlField.ts @@ -1,6 +1,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, primitive } from "serializr"; -import { ObjectField, Copy } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString } from "./FieldSymbols"; @Deserializable("html") export class HtmlField extends ObjectField { @@ -15,4 +16,8 @@ export class HtmlField extends ObjectField { [Copy]() { return new HtmlField(this.html); } + + [ToScriptString]() { + return "invalid"; + } } diff --git a/src/new_fields/IconField.ts b/src/new_fields/IconField.ts index 1a928389d..62b2cd254 100644 --- a/src/new_fields/IconField.ts +++ b/src/new_fields/IconField.ts @@ -1,6 +1,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, primitive } from "serializr"; -import { ObjectField, Copy } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString } from "./FieldSymbols"; @Deserializable("icon") export class IconField extends ObjectField { @@ -15,4 +16,8 @@ export class IconField extends ObjectField { [Copy]() { return new IconField(this.icon); } + + [ToScriptString]() { + return "invalid"; + } } diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 2d75f8a19..4e3b7abe0 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -1,6 +1,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; -import { ObjectField, Copy } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString } from "./FieldSymbols"; import { deepCopy } from "../Utils"; export enum InkTool { @@ -40,4 +41,8 @@ export class InkField extends ObjectField { [Copy]() { return new InkField(deepCopy(this.inkData)); } + + [ToScriptString]() { + return "invalid"; + } } diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index 70e36f911..f1e4c4721 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -1,11 +1,12 @@ import { Deserializable, autoObject } from "../client/util/SerializationHelper"; -import { Field, Update, Self, FieldResult, SelfProxy } from "./Doc"; +import { Field } from "./Doc"; import { setter, getter, deleteProperty, updateFunction } from "./util"; import { serializable, alias, list } from "serializr"; import { observable, action } from "mobx"; -import { ObjectField, OnUpdate, Copy, Parent } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; import { RefField } from "./RefField"; import { ProxyField } from "./Proxy"; +import { Self, Update, Parent, OnUpdate, SelfProxy, ToScriptString, Copy } from "./FieldSymbols"; const listHandlers: any = { /// Mutator methods @@ -225,7 +226,7 @@ type StoredType = T extends RefField ? ProxyField : T; @Deserializable("list") class ListImpl extends ObjectField { - constructor(fields: T[] = []) { + constructor(fields?: T[]) { super(); const list = new Proxy(this, { set: setter, @@ -244,7 +245,9 @@ class ListImpl extends ObjectField { defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, }); this[SelfProxy] = list; - (list as any).push(...fields); + if (fields) { + (list as any).push(...fields); + } return list; } @@ -284,6 +287,11 @@ class ListImpl extends ObjectField { private [Self] = this; private [SelfProxy]: any; + + [ToScriptString]() { + return "invalid"; + // return `new List([${(this as any).map((field => Field.toScriptString(field))}])`; + } } export type List = ListImpl & (T | (T extends RefField ? Promise : never))[]; export const List: { new (fields?: T[]): List } = ListImpl as any; \ No newline at end of file diff --git a/src/new_fields/ObjectField.ts b/src/new_fields/ObjectField.ts index 51768c6db..5f4a6f8fb 100644 --- a/src/new_fields/ObjectField.ts +++ b/src/new_fields/ObjectField.ts @@ -1,14 +1,13 @@ import { Doc } from "./Doc"; import { RefField } from "./RefField"; - -export const OnUpdate = Symbol("OnUpdate"); -export const Parent = Symbol("Parent"); -export const Copy = Symbol("Copy"); +import { OnUpdate, Parent, Copy, ToScriptString } from "./FieldSymbols"; export abstract class ObjectField { protected [OnUpdate](diff?: any) { } private [Parent]?: RefField | ObjectField; abstract [Copy](): ObjectField; + + abstract [ToScriptString](): string; } export namespace ObjectField { diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts index fd99ae1c0..130ec066e 100644 --- a/src/new_fields/Proxy.ts +++ b/src/new_fields/Proxy.ts @@ -3,8 +3,9 @@ import { FieldWaiting } from "./Doc"; import { primitive, serializable } from "serializr"; import { observable, action } from "mobx"; import { DocServer } from "../client/DocServer"; -import { RefField, Id } from "./RefField"; -import { ObjectField, Copy } from "./ObjectField"; +import { RefField } from "./RefField"; +import { ObjectField } from "./ObjectField"; +import { Id, Copy, ToScriptString } from "./FieldSymbols"; @Deserializable("proxy") export class ProxyField extends ObjectField { @@ -26,6 +27,10 @@ export class ProxyField extends ObjectField { return new ProxyField(this.fieldId); } + [ToScriptString]() { + return "invalid"; + } + @serializable(primitive()) readonly fieldId: string = ""; diff --git a/src/new_fields/RefField.ts b/src/new_fields/RefField.ts index 202c65f21..75ce4287f 100644 --- a/src/new_fields/RefField.ts +++ b/src/new_fields/RefField.ts @@ -1,9 +1,8 @@ import { serializable, primitive, alias } from "serializr"; import { Utils } from "../Utils"; +import { Id, HandleUpdate, ToScriptString } from "./FieldSymbols"; export type FieldId = string; -export const HandleUpdate = Symbol("HandleUpdate"); -export const Id = Symbol("Id"); export abstract class RefField { @serializable(alias("id", primitive())) private __id: FieldId; @@ -15,4 +14,6 @@ export abstract class RefField { } protected [HandleUpdate]?(diff: any): void; + + abstract [ToScriptString](): string; } diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts index eb30e76de..89d077a47 100644 --- a/src/new_fields/RichTextField.ts +++ b/src/new_fields/RichTextField.ts @@ -1,6 +1,7 @@ -import { ObjectField, Copy } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; import { serializable } from "serializr"; import { Deserializable } from "../client/util/SerializationHelper"; +import { Copy, ToScriptString } from "./FieldSymbols"; @Deserializable("RichTextField") export class RichTextField extends ObjectField { @@ -15,4 +16,8 @@ export class RichTextField extends ObjectField { [Copy]() { return new RichTextField(this.Data); } + + [ToScriptString]() { + return "invalid"; + } } \ No newline at end of file diff --git a/src/new_fields/URLField.ts b/src/new_fields/URLField.ts index d00a95a16..a6f8f1cc5 100644 --- a/src/new_fields/URLField.ts +++ b/src/new_fields/URLField.ts @@ -1,6 +1,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom } from "serializr"; -import { ObjectField, Copy } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; +import { ToScriptString, Copy } from "./FieldSymbols"; function url() { return custom( @@ -13,7 +14,7 @@ function url() { ); } -export class URLField extends ObjectField { +export abstract class URLField extends ObjectField { @serializable(url()) readonly url: URL; @@ -22,6 +23,10 @@ export class URLField extends ObjectField { this.url = url; } + [ToScriptString]() { + return `new ${this.constructor.name}(new URL(${this.url.href}))`; + } + [Copy](): this { return new (this.constructor as any)(this.url); } diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index d94994a07..65a37a0d1 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -1,11 +1,12 @@ import { UndoManager } from "../client/util/UndoManager"; -import { Update, Doc, Field } from "./Doc"; +import { Doc, Field } from "./Doc"; import { SerializationHelper } from "../client/util/SerializationHelper"; import { ProxyField } from "./Proxy"; import { FieldValue } from "./Types"; -import { RefField, Id } from "./RefField"; -import { ObjectField, Parent, OnUpdate } from "./ObjectField"; +import { RefField } from "./RefField"; +import { ObjectField } from "./ObjectField"; import { action } from "mobx"; +import { Parent, OnUpdate, Update, Id } from "./FieldSymbols"; export const setter = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean { if (SerializationHelper.IsSerializing()) { -- cgit v1.2.3-70-g09d2 From 6eb5234a0def9e5714319e512e8dd927bd894b82 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 21 May 2019 11:44:51 -0400 Subject: Fixed various scripting things --- src/client/util/type_decls.d | 33 ++++++++++++++++------ .../views/collections/CollectionSchemaView.tsx | 10 +++---- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/KeyValuePair.tsx | 8 ++---- src/debug/Viewer.tsx | 2 +- src/new_fields/Doc.ts | 7 +++-- src/new_fields/URLField.ts | 9 ++++-- 7 files changed, 46 insertions(+), 25 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d index 51114d0e2..557f6f574 100644 --- a/src/client/util/type_decls.d +++ b/src/client/util/type_decls.d @@ -140,33 +140,50 @@ declare const ToScriptString: unique symbol; declare abstract class RefField { readonly [Id]: FieldId; - constructor(id?: FieldId); - protected [HandleUpdate]?(diff: any): void; + constructor(); + // protected [HandleUpdate]?(diff: any): void; - abstract [ToScriptString](): string; + // abstract [ToScriptString](): string; } declare abstract class ObjectField { protected [OnUpdate](diff?: any): void; private [Parent]?: RefField | ObjectField; - abstract [Copy](): ObjectField; + // abstract [Copy](): ObjectField; - abstract [ToScriptString](): string; + // abstract [ToScriptString](): string; } + +declare abstract class URLField extends ObjectField { + readonly url: URL; + + constructor(url: string); + constructor(url: URL); +} + +declare class AudioField extends URLField { } +declare class VideoField extends URLField { } +declare class ImageField extends URLField { } +declare class WebField extends URLField { } +declare class PdfField extends URLField { } + declare type FieldId = string; declare type Field = number | string | boolean | ObjectField | RefField; declare type Opt = T | undefined; declare class Doc extends RefField { + constructor(); + [key: string]: Field | undefined; - [ToScriptString](): string; + // [ToScriptString](): string; } declare class ListImpl extends ObjectField { + constructor(fields?: T[]); [index: number]: T | (T extends RefField ? Promise : never); - [ToScriptString](): string; - [Copy](): ObjectField; + // [ToScriptString](): string; + // [Copy](): ObjectField; } // @ts-ignore diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index b25b48339..488f7d6cb 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -115,22 +115,20 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { height={Number(MAX_ROW_HEIGHT)} GetValue={() => { let field = props.Document[props.fieldKey]; - if (field) { - //TODO Types - // return field.ToScriptString(); - return String(field); + if (Field.IsField(field)) { + return Field.toScriptString(field); } return ""; }} SetValue={(value: string) => { - let script = CompileScript(value, { addReturn: true, params: { this: Document.name } }); + let script = CompileScript(value, { addReturn: true, params: { this: Doc.name } }); if (!script.compiled) { return false; } return applyToDoc(props.Document, script.run); }} OnFillDown={async (value: string) => { - let script = CompileScript(value, { addReturn: true, params: { this: Document.name } }); + let script = CompileScript(value, { addReturn: true, params: { this: Doc.name } }); if (!script.compiled) { return; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ba6a4bbab..7a0a02318 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -183,7 +183,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return; } e.stopPropagation(); - const coefficient = 100; + const coefficient = 1000; if (e.ctrlKey) { let deltaScale = (1 - (e.deltaY / coefficient)); diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 7a88985c0..2363553df 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -60,10 +60,8 @@ export class KeyValuePair extends React.Component { { let field = FieldValue(props.Document[props.fieldKey]); - if (field) { - //TODO Types - return String(field); - // return field.ToScriptString(); + if (Field.IsField(field)) { + return Field.toScriptString(field); } return ""; }} @@ -75,7 +73,7 @@ export class KeyValuePair extends React.Component { let res = script.run(); if (!res.success) return false; const field = res.result; - if (Field.IsField(field)) { + if (Field.IsField(field, true)) { props.Document[props.fieldKey] = field; return true; } diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index 4314e2132..b22300d0b 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -20,7 +20,7 @@ function applyToDoc(doc: any, key: string | number, scriptString: string): boole } const res = script.run({ this: doc }); if (!res.success) return false; - if (!Field.IsField(res.result)) return false; + if (!Field.IsField(res.result, true)) return false; doc[key] = res.result; return true; } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 08bc2ec4d..b0237d04d 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -19,12 +19,15 @@ export namespace Field { return field[ToScriptString](); } } - export function IsField(field: any): field is Field { + export function IsField(field: any): field is Field; + export function IsField(field: any, includeUndefined: true): field is Field | undefined; + export function IsField(field: any, includeUndefined: boolean = false): field is Field | undefined { return (typeof field === "string") || (typeof field === "number") || (typeof field === "boolean") || (field instanceof ObjectField) - || (field instanceof RefField); + || (field instanceof RefField) + || (includeUndefined && field === undefined); } } export type Field = number | string | boolean | ObjectField | RefField; diff --git a/src/new_fields/URLField.ts b/src/new_fields/URLField.ts index a6f8f1cc5..4a2841fb6 100644 --- a/src/new_fields/URLField.ts +++ b/src/new_fields/URLField.ts @@ -18,13 +18,18 @@ export abstract class URLField extends ObjectField { @serializable(url()) readonly url: URL; - constructor(url: URL) { + constructor(url: string); + constructor(url: URL); + constructor(url: URL | string) { super(); + if (typeof url === "string") { + url = new URL(url); + } this.url = url; } [ToScriptString]() { - return `new ${this.constructor.name}(new URL(${this.url.href}))`; + return `new ${this.constructor.name}("${this.url.href}")`; } [Copy](): this { -- cgit v1.2.3-70-g09d2 From 2c4026368078e2dc856c1cf4f8fe375cd30fbcdd Mon Sep 17 00:00:00 2001 From: ab Date: Tue, 21 May 2019 18:03:27 -0400 Subject: alt and linking --- src/client/util/DocumentManager.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index a5e768dcf..82776ff59 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -125,10 +125,20 @@ export class DocumentManager { } let docView = DocumentManager.Instance.getDocumentView(doc); if (docView) { - docView.props.focus(docView.props.Document); + console.log("navigating to linked doc..."); + // using makecopy as a flag for splitting linked to doc to the right...can change later if needed + if (makeCopy) { + if (!contextDoc) { + const actualDoc = Doc.MakeAlias(docDelegate); + (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc); + } + } + else { + docView.props.focus(docView.props.Document); + } } else { if (!contextDoc) { - const actualDoc = docDelegate ? (makeCopy ? Doc.MakeCopy(docDelegate) : docDelegate) : Doc.MakeDelegate(doc); + const actualDoc = Doc.MakeAlias(docDelegate); (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc); } else { let contextView = DocumentManager.Instance.getDocumentView(contextDoc); -- cgit v1.2.3-70-g09d2 From f196645935814b7f2d3faef0da7fd6c5d46f14f0 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 21 May 2019 18:04:16 -0400 Subject: various fixes --- src/client/util/SearchUtil.ts | 3 +- src/client/views/MainOverlayTextBox.tsx | 2 +- .../views/collections/CollectionTreeView.scss | 4 +- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/KeyValuePair.tsx | 3 +- .../authentication/models/current_user_utils.ts | 46 +++++++++++----------- 6 files changed, 32 insertions(+), 28 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index e8eb70837..28ec8ca14 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -20,6 +20,7 @@ export namespace SearchUtil { export async function GetAliasesOfDocument(doc: Doc): Promise { const proto = await Doc.GetT(doc, "proto", Doc, true); const protoId = (proto || doc)[Id]; - return Search(`{!join from=id to=proto_i}id:${protoId}`, true); + return Search(`proto_i:"${protoId}"`, true); + // return Search(`{!join from=id to=proto_i}id:${protoId}`, true); } } \ No newline at end of file diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 91f626737..9be408049 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -90,7 +90,7 @@ export class MainOverlayTextBox extends React.Component style={{ width: `${textRect.width * s}px`, height: `${textRect.height * s}px` }}> + ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={emptyFunction} /> ; } diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 5f82137c6..2f0329fc4 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -46,7 +46,9 @@ .docContainer:hover { .treeViewItem-openRight { - display: inline; + display: inline-block; + // display: inline; + transform: translate(0px, -3px); //TODO Fix this } } diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 092ccb9b0..d3d765eed 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -35,7 +35,7 @@ export interface FieldViewProps { isTopMost: boolean; selectOnLoad: boolean; addDocument?: (document: Doc, allowDuplicates?: boolean) => boolean; - addDocTab: (document: Doc, where: string) => boolean; + addDocTab: (document: Doc, where: string) => void; removeDocument?: (document: Doc) => boolean; moveDocument?: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; ScreenToLocalTransform: () => Transform; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 2363553df..228d07018 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,7 +1,7 @@ import { action, observable } from 'mobx'; import { observer } from "mobx-react"; import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app -import { emptyFunction, returnFalse, returnZero } from '../../../Utils'; +import { emptyFunction, returnFalse, returnZero, returnTrue } from '../../../Utils'; import { CompileScript } from "../../util/Scripting"; import { Transform } from '../../util/Transform'; import { EditableView } from "../EditableView"; @@ -38,6 +38,7 @@ export class KeyValuePair extends React.Component { focus: emptyFunction, PanelWidth: returnZero, PanelHeight: returnZero, + addDocTab: emptyFunction }; let contents = ; let fieldKey = Object.keys(props.Document).indexOf(props.fieldKey) !== -1 ? props.fieldKey : "(" + props.fieldKey + ")"; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index aef2d3f4a..b947f5e01 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -83,29 +83,29 @@ export class CurrentUserUtils { @action static SetNorthstarCatalog(ctlog: Catalog, extras: Catalog[]) { CurrentUserUtils.NorthstarDBCatalog = ctlog; - if (ctlog && ctlog.schemas) { - extras.map(ex => ctlog.schemas!.push(ex)); - return ctlog.schemas.map(async schema => { - let schemaDocuments: Doc[] = []; - let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema); - await Promise.all(attributesToBecomeDocs.reduce((promises, attr) => { - promises.push(DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt) => { - if (field instanceof Doc) { - schemaDocuments.push(field); - } else { - var atmod = new ColumnAttributeModel(attr); - let histoOp = new HistogramOperation(schema.displayName!, - new AttributeTransformationModel(atmod, AggregateFunction.None), - new AttributeTransformationModel(atmod, AggregateFunction.Count), - new AttributeTransformationModel(atmod, AggregateFunction.Count)); - schemaDocuments.push(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! })); - } - }))); - return promises; - }, [] as Promise[])); - return CurrentUserUtils._northstarSchemas.push(Docs.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! })); - }); - } + // if (ctlog && ctlog.schemas) { + // extras.map(ex => ctlog.schemas!.push(ex)); + // return ctlog.schemas.map(async schema => { + // let schemaDocuments: Doc[] = []; + // let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema); + // await Promise.all(attributesToBecomeDocs.reduce((promises, attr) => { + // promises.push(DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt) => { + // if (field instanceof Doc) { + // schemaDocuments.push(field); + // } else { + // var atmod = new ColumnAttributeModel(attr); + // let histoOp = new HistogramOperation(schema.displayName!, + // new AttributeTransformationModel(atmod, AggregateFunction.None), + // new AttributeTransformationModel(atmod, AggregateFunction.Count), + // new AttributeTransformationModel(atmod, AggregateFunction.Count)); + // schemaDocuments.push(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! })); + // } + // }))); + // return promises; + // }, [] as Promise[])); + // return CurrentUserUtils._northstarSchemas.push(Docs.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! })); + // }); + // } } public static set NorthstarDBCatalog(ctlog: Catalog | undefined) { this._northstarCatalog = ctlog; } -- cgit v1.2.3-70-g09d2 From 2845bb8a29d4592964b707d82ca3b07ca15b632c Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 21 May 2019 18:30:48 -0400 Subject: Added highlighting of target doc --- src/client/util/DocumentManager.ts | 3 ++- src/new_fields/Doc.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index a5e768dcf..94d77f467 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -116,13 +116,14 @@ export class DocumentManager { @undoBatch public jumpToDocument = async (docDelegate: Doc, makeCopy: boolean = true, dockFunc?: (doc: Doc) => void): Promise => { - let doc = docDelegate.proto ? docDelegate.proto : docDelegate; + let doc = Doc.GetProto(docDelegate); const page = NumCast(doc.page, undefined); const contextDoc = await Cast(doc.annotationOn, Doc); if (contextDoc) { const curPage = NumCast(contextDoc.curPage, page); if (page !== curPage) contextDoc.curPage = page; } + docDelegate.libraryBrush = true; let docView = DocumentManager.Instance.getDocumentView(doc); if (docView) { docView.props.focus(docView.props.Document); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index b0237d04d..793a83750 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -194,7 +194,7 @@ export namespace Doc { // gets the document's prototype or returns the document if it is a prototype export function GetProto(doc: Doc) { - return Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto! : doc; + return Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : doc.proto!; } -- cgit v1.2.3-70-g09d2 From 3020cfcf20d187c976a7f386a95bec0c41cba06b Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 21 May 2019 18:35:04 -0400 Subject: fixes --- src/client/util/DocumentManager.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/client/util') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 94d77f467..fefd3a972 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -123,16 +123,18 @@ export class DocumentManager { const curPage = NumCast(contextDoc.curPage, page); if (page !== curPage) contextDoc.curPage = page; } - docDelegate.libraryBrush = true; let docView = DocumentManager.Instance.getDocumentView(doc); if (docView) { + docView.props.Document.libraryBrush = true; docView.props.focus(docView.props.Document); } else { if (!contextDoc) { const actualDoc = docDelegate ? (makeCopy ? Doc.MakeCopy(docDelegate) : docDelegate) : Doc.MakeDelegate(doc); + actualDoc.libraryBrush = true; (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc); } else { let contextView = DocumentManager.Instance.getDocumentView(contextDoc); + docDelegate.libraryBrush = true; if (contextView) { contextDoc.panTransformType = "Ease"; contextView.props.focus(contextDoc); -- cgit v1.2.3-70-g09d2 From 72fae9407783a6d17d8d5e202ae0a8d379f57da7 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 21 May 2019 19:12:10 -0400 Subject: Changes to DocumentManager --- src/client/util/DocumentManager.ts | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index cf470a015..369becccb 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -123,30 +123,20 @@ export class DocumentManager { const curPage = NumCast(contextDoc.curPage, page); if (page !== curPage) contextDoc.curPage = page; } - let docView = DocumentManager.Instance.getDocumentView(doc); - if (docView) { - console.log("navigating to linked doc..."); - // using makecopy as a flag for splitting linked to doc to the right...can change later if needed - if (makeCopy) { - if (!contextDoc) { - const actualDoc = Doc.MakeAlias(docDelegate); - actualDoc.libraryBrush = true; - (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc); - } - } - else { - docView.props.Document.libraryBrush = true; - docView.props.focus(docView.props.Document); - } + let docView: DocumentView | null; + // using makecopy as a flag for splitting linked to doc to the right...can change later if needed + if (!makeCopy && (docView = DocumentManager.Instance.getDocumentView(doc))) { + docView.props.Document.libraryBrush = true; + docView.props.focus(docView.props.Document); } else { if (!contextDoc) { const actualDoc = Doc.MakeAlias(docDelegate); - + actualDoc.libraryBrush = true; (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc); } else { - let contextView = DocumentManager.Instance.getDocumentView(contextDoc); + let contextView: DocumentView | null; docDelegate.libraryBrush = true; - if (contextView) { + if (!makeCopy && (contextView = DocumentManager.Instance.getDocumentView(contextDoc))) { contextDoc.panTransformType = "Ease"; contextView.props.focus(contextDoc); } else { -- cgit v1.2.3-70-g09d2 From dcfbe047add9768f21d84b06a3ed45e11295a15f Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 22 May 2019 11:07:20 -0400 Subject: fixed presentation view link follow default. --- src/client/util/DocumentManager.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 369becccb..f113ff1d7 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -115,7 +115,7 @@ export class DocumentManager { } @undoBatch - public jumpToDocument = async (docDelegate: Doc, makeCopy: boolean = true, dockFunc?: (doc: Doc) => void): Promise => { + public jumpToDocument = async (docDelegate: Doc, forceDockFunc: boolean = false, dockFunc?: (doc: Doc) => void): Promise => { let doc = Doc.GetProto(docDelegate); const page = NumCast(doc.page, undefined); const contextDoc = await Cast(doc.annotationOn, Doc); @@ -124,8 +124,8 @@ export class DocumentManager { if (page !== curPage) contextDoc.curPage = page; } let docView: DocumentView | null; - // using makecopy as a flag for splitting linked to doc to the right...can change later if needed - if (!makeCopy && (docView = DocumentManager.Instance.getDocumentView(doc))) { + // using forceDockFunc as a flag for splitting linked to doc to the right...can change later if needed + if (!forceDockFunc && (docView = DocumentManager.Instance.getDocumentView(doc))) { docView.props.Document.libraryBrush = true; docView.props.focus(docView.props.Document); } else { @@ -136,7 +136,7 @@ export class DocumentManager { } else { let contextView: DocumentView | null; docDelegate.libraryBrush = true; - if (!makeCopy && (contextView = DocumentManager.Instance.getDocumentView(contextDoc))) { + if (!forceDockFunc && (contextView = DocumentManager.Instance.getDocumentView(contextDoc))) { contextDoc.panTransformType = "Ease"; contextView.props.focus(contextDoc); } else { -- cgit v1.2.3-70-g09d2 From 30fdae9e869e0f132c76b4fa99b784e75d6c8dae Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 22 May 2019 19:51:49 -0400 Subject: A bunch of fixes/changes --- src/client/documents/Documents.ts | 2 + src/client/util/DocumentManager.ts | 6 ++- src/client/views/InkingCanvas.scss | 42 ++++++++++++-------- src/client/views/SearchBox.tsx | 10 +++-- .../views/collections/CollectionPDFView.scss | 39 ++++++++++-------- src/client/views/collections/CollectionSubView.tsx | 4 ++ .../views/collections/CollectionVideoView.tsx | 46 +++++++++++++++++++++- .../collections/collectionFreeForm/MarqueeView.tsx | 5 ++- .../views/nodes/CollectionFreeFormDocumentView.tsx | 9 ++++- src/client/views/nodes/DocumentView.tsx | 12 +++--- src/client/views/nodes/ImageBox.tsx | 6 ++- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 16 +++++++- src/client/views/nodes/VideoBox.tsx | 8 +++- 14 files changed, 153 insertions(+), 54 deletions(-) (limited to 'src/client/util') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 323534b2b..ae190a989 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -77,7 +77,9 @@ export namespace DocUtils { linkDoc.proto!.linkTags = "Default"; linkDoc.proto!.linkedTo = target; + linkDoc.proto!.linkedToPage = target.curPage; linkDoc.proto!.linkedFrom = source; + linkDoc.proto!.linkedFromPage = source.curPage; let linkedFrom = Cast(protoTarg.linkedFromDocs, listSpec(Doc)); if (!linkedFrom) { diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index f113ff1d7..65c4b9e4b 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -115,11 +115,11 @@ export class DocumentManager { } @undoBatch - public jumpToDocument = async (docDelegate: Doc, forceDockFunc: boolean = false, dockFunc?: (doc: Doc) => void): Promise => { + public jumpToDocument = async (docDelegate: Doc, forceDockFunc: boolean = false, dockFunc?: (doc: Doc) => void, linkPage?: number): Promise => { let doc = Doc.GetProto(docDelegate); - const page = NumCast(doc.page, undefined); const contextDoc = await Cast(doc.annotationOn, Doc); if (contextDoc) { + const page = NumCast(doc.page, linkPage || 0); const curPage = NumCast(contextDoc.curPage, page); if (page !== curPage) contextDoc.curPage = page; } @@ -127,11 +127,13 @@ export class DocumentManager { // using forceDockFunc as a flag for splitting linked to doc to the right...can change later if needed if (!forceDockFunc && (docView = DocumentManager.Instance.getDocumentView(doc))) { docView.props.Document.libraryBrush = true; + if (linkPage !== undefined) docView.props.Document.curPage = linkPage; docView.props.focus(docView.props.Document); } else { if (!contextDoc) { const actualDoc = Doc.MakeAlias(docDelegate); actualDoc.libraryBrush = true; + if (linkPage !== undefined) actualDoc.curPage = linkPage; (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc); } else { let contextView: DocumentView | null; diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss index 8bcaf41dd..d95398f17 100644 --- a/src/client/views/InkingCanvas.scss +++ b/src/client/views/InkingCanvas.scss @@ -1,40 +1,50 @@ @import "globalCssVariables"; .inkingCanvas { - opacity:0.99; + opacity: 0.99; + .jsx-parser { - position:absolute; - width:100%; - height:100%; + position: absolute; + width: 100%; + height: 100%; + z-index: -1; // allows annotations to appear on videos when screen is full-size & ... } } -.inkingCanvas-paths-ink, .inkingCanvas-paths-markers, .inkingCanvas-noSelect, .inkingCanvas-canSelect { + +.inkingCanvas-paths-ink, +.inkingCanvas-paths-markers, +.inkingCanvas-noSelect, +.inkingCanvas-canSelect { position: absolute; top: 0; - left:0; + left: 0; width: 8192px; height: 8192px; - cursor:"crosshair"; + cursor: "crosshair"; pointer-events: auto; - + } -.inkingCanvas-canSelect, -.inkingCanvas-noSelect { - top:-50000px; - left:-50000px; + +.inkingCanvas-canSelect, +.inkingCanvas-noSelect { + top: -50000px; + left: -50000px; width: 100000px; height: 100000px; } -.inkingCanvas-noSelect { + +.inkingCanvas-noSelect { pointer-events: none; cursor: "arrow"; } -.inkingCanvas-paths-ink, .inkingCanvas-paths-markers { + +.inkingCanvas-paths-ink, +.inkingCanvas-paths-markers { pointer-events: none; z-index: 10000; // overlays ink on top of everything cursor: "arrow"; } + .inkingCanvas-paths-markers { mix-blend-mode: multiply; -} - +} \ No newline at end of file diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 911fc8d9c..fa9462acf 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -21,6 +21,7 @@ import { DocumentManager } from '../util/DocumentManager'; import { SetupDrag } from '../util/DragManager'; import { Docs } from '../documents/Documents'; import { RouteStore } from '../../server/RouteStore'; +import { NumCast } from '../../new_fields/Types'; library.add(faSearch); library.add(faObjectGroup); @@ -143,18 +144,21 @@ export class SearchBox extends React.Component { }); let x = 0; let y = 0; + let maxy = 300; for (const doc of docs) { doc.x = x; doc.y = y; doc.width = 200; - doc.height = 200; + doc.height = 200 * NumCast(doc.nativeHeight) / NumCast(doc.nativeWidth, 1); + maxy = Math.max(doc.height, maxy); x += 250; if (x > 1000) { + maxy = 300; x = 0; - y += 250; + y += maxy + 25; } } - return Docs.FreeformDocument(docs, { width: 400, height: 400, panX: 175, panY: 175, title: `Search Docs: "${this.searchString}"` }); + return Docs.FreeformDocument(docs, { width: 400, height: 400, panX: 175, panY: 175, backgroundColor: "grey", title: `Search Docs: "${this.searchString}"` }); } // Useful queries: diff --git a/src/client/views/collections/CollectionPDFView.scss b/src/client/views/collections/CollectionPDFView.scss index f6fb79582..50201bae8 100644 --- a/src/client/views/collections/CollectionPDFView.scss +++ b/src/client/views/collections/CollectionPDFView.scss @@ -1,49 +1,56 @@ .collectionPdfView-buttonTray { - top : 15px; - left : 20px; - position: relative; + top: 15px; + left: 20px; + position: relative; transform-origin: left top; position: absolute; } + .collectionPdfView-thumb { - width:25px; - height:25px; + width: 25px; + height: 25px; transform-origin: left top; position: absolute; background: darkgray; } + .collectionPdfView-slider { - width:25px; - height:25px; + width: 25px; + height: 25px; transform-origin: left top; position: absolute; background: lightgray; } -.collectionPdfView-cont{ + +.collectionPdfView-cont { width: 100%; height: 100%; - position: absolute; + position: absolute; top: 0; - left:0; + left: 0; + z-index: -1; } + .collectionPdfView-cont-dragging { span { user-select: none; } } + .collectionPdfView-backward { - color : white; + color: white; font-size: 24px; - top :0px; - left : 0px; + top: 0px; + left: 0px; position: absolute; background-color: rgba(50, 50, 50, 0.2); } + .collectionPdfView-forward { - color : white; + color: white; font-size: 24px; - top :0px; - left : 45px; + top: 0px; + left: 45px; position: absolute; background-color: rgba(50, 50, 50, 0.2); } \ No newline at end of file diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 7800b35df..4a21e4465 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -153,6 +153,10 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { @undoBatch @action protected onDrop(e: React.DragEvent, options: DocumentOptions): void { + if (e.ctrlKey) { + e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl + return; + } let html = e.dataTransfer.getData("text/html"); let text = e.dataTransfer.getData("text/plain"); diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 27f23a1a8..7853544d5 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -1,4 +1,5 @@ import { action, observable, trace } from "mobx"; +import * as htmlToImage from "html-to-image"; import { observer } from "mobx-react"; import { ContextMenu } from "../ContextMenu"; import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView"; @@ -6,10 +7,14 @@ import React = require("react"); import "./CollectionVideoView.scss"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; -import { emptyFunction } from "../../../Utils"; +import { emptyFunction, Utils } from "../../../Utils"; import { Id } from "../../../new_fields/FieldSymbols"; import { VideoBox } from "../nodes/VideoBox"; -import { NumCast } from "../../../new_fields/Types"; +import { NumCast, Cast, StrCast } from "../../../new_fields/Types"; +import { VideoField } from "../../../new_fields/URLField"; +import { SearchBox } from "../SearchBox"; +import { DocServer } from "../../DocServer"; +import { Docs, DocUtils } from "../../documents/Documents"; @observer @@ -67,6 +72,43 @@ export class CollectionVideoView extends React.Component { onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 } + + let field = Cast(this.props.Document[this.props.fieldKey], VideoField); + if (field) { + let url = field.url.href; + ContextMenu.Instance.addItem({ + description: "Copy path", event: () => { Utils.CopyText(url); }, icon: "expand-arrows-alt" + }); + } + let width = NumCast(this.props.Document.width); + let height = NumCast(this.props.Document.height); + ContextMenu.Instance.addItem({ + description: "Take Snapshot", event: async () => { + var canvas = document.createElement('canvas'); + canvas.width = 640; + canvas.height = 640 * NumCast(this.props.Document.nativeHeight) / NumCast(this.props.Document.nativeWidth); + var ctx = canvas.getContext('2d');//draw image to canvas. scale to target dimensions + ctx && ctx.drawImage(this._videoBox!.player!, 0, 0, canvas.width, canvas.height); + + //convert to desired file format + var dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png' + // if you want to preview the captured image, + + let filename = encodeURIComponent("snapshot" + this.props.Document.title + "_" + this.props.Document.curPage).replace(/\./g, ""); + SearchBox.convertDataUri(dataUrl, filename).then((returnedFilename) => { + if (returnedFilename) { + let url = DocServer.prepend(returnedFilename); + let imageSummary = Docs.ImageDocument(url, { + x: NumCast(this.props.Document.x) + width, y: NumCast(this.props.Document.y), + width: 150, height: height / width * 150, title: "--snapshot" + NumCast(this.props.Document.curPage) + " image-" + }); + this.props.addDocument && this.props.addDocument(imageSummary, false); + DocUtils.MakeLink(imageSummary, this.props.Document); + } + }); + }, + icon: "expand-arrows-alt" + }); } setVideoBox = (videoBox: VideoBox) => { this._videoBox = videoBox; }; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index d72046800..973ebfbdd 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -296,7 +296,10 @@ export class MarqueeView extends React.Component SearchBox.convertDataUri(dataUrl, "icon" + summary[Id] + "_image").then((returnedFilename) => { if (returnedFilename) { let url = DocServer.prepend(returnedFilename); - let imageSummary = Docs.ImageDocument(url, { x: bounds.left, y: bounds.top + 100 / zoomBasis, width: 150, title: "-summary image-" }); + let imageSummary = Docs.ImageDocument(url, { + x: bounds.left, y: bounds.top + 100 / zoomBasis, + width: 150, height: bounds.height / bounds.width * 150, title: "-summary image-" + }); summary.imageSummary = imageSummary; this.props.addDocument(imageSummary, false); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index aaaa6a9c5..66d91f9c2 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -195,6 +195,7 @@ export class CollectionFreeFormDocumentView extends DocComponent l instanceof Promise)) { let maxLocation = StrCast(linkedFwdDocs[altKey ? 1 : 0].maximizeLocation, "inTab"); - DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], altKey, document => this.props.addDocTab(document, maxLocation)); + DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, document => this.props.addDocTab(document, maxLocation), linkedFwdPage[altKey ? 1 : 0]); } } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 87c88f57c..01c4d82fb 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -234,12 +234,14 @@ export class DocumentView extends DocComponent(Docu makeButton = (e: React.MouseEvent): void => { let doc = this.props.Document.proto ? this.props.Document.proto : this.props.Document; doc.isButton = !BoolCast(doc.isButton, false); - if (doc.isButton && !doc.nativeWidth) { - doc.nativeWidth = this.props.Document[WidthSym](); - doc.nativeHeight = this.props.Document[HeightSym](); - } else { + if (StrCast(doc.layout).indexOf("Formatted") !== -1) { // only need to freeze the dimensions of text boxes since they don't have a native width and height naturally + if (doc.isButton && !doc.nativeWidth) { + doc.nativeWidth = this.props.Document[WidthSym](); + doc.nativeHeight = this.props.Document[HeightSym](); + } else { - doc.nativeWidth = doc.nativeHeight = undefined; + doc.nativeWidth = doc.nativeHeight = undefined; + } } } fullScreenClicked = (e: React.MouseEvent): void => { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 71bda6fea..cc0dc8220 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -47,7 +47,7 @@ export class ImageBox extends DocComponent(ImageD onLoad = (target: any) => { var h = this._imgRef.current!.naturalHeight; var w = this._imgRef.current!.naturalWidth; - if (this._photoIndex === 0 && (this.props as any).id !== "isExpander" && (!this.Document.nativeHeight || !this.Document.nativeWidth)) { + if (this._photoIndex === 0 && (this.props as any).id !== "isExpander" && (!this.Document.nativeWidth || !this.Document.nativeHeight || Math.abs(this.Document.nativeWidth / this.Document.nativeHeight - w / h) > 0.05)) { Doc.SetOnPrototype(this.Document, "nativeHeight", FieldValue(this.Document.nativeWidth, 0) * h / w); this.Document.height = FieldValue(this.Document.width, 0) * h / w; } @@ -165,8 +165,10 @@ export class ImageBox extends DocComponent(ImageD } choosePath(url: URL) { - if (url.protocol === "data" || url.href.indexOf(window.location.origin) === -1) + const lower = url.href.toLowerCase(); + if (url.protocol === "data" || url.href.indexOf(window.location.origin) === -1 || !(lower.endsWith(".png") || lower.endsWith(".jpg") || lower.endsWith(".jpeg"))) { return url.href; + } let ext = path.extname(url.href); return url.href.replace(ext, this._curSuffix + ext); } diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 8cb576786..849f17aa4 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -78,7 +78,7 @@ export class KeyValueBox extends React.Component { let rows: JSX.Element[] = []; let i = 0; - for (let key in ids) { + for (let key of Object.keys(ids).sort()) { rows.push(); } return rows; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 5b8b15ed8..733bc920f 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -23,6 +23,7 @@ import { pageSchema } from "./ImageBox"; import "./PDFBox.scss"; var path = require('path'); import React = require("react"); +import { ContextMenu } from "../ContextMenu"; /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx * This method renders PDF and puts all kinds of functionalities such as annotation, highlighting, @@ -357,7 +358,7 @@ export class PDFBox extends DocComponent(PdfDocumen @computed get imageProxyRenderer() { let thumbField = this.props.Document.thumbnail; - if (thumbField && this._renderAsSvg) { + if (thumbField && this._renderAsSvg && NumCast(this.props.Document.thumbnailPage, 0) === this.Document.curPage) { // let transform = this.props.ScreenToLocalTransform().inverse(); let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50; @@ -380,10 +381,21 @@ export class PDFBox extends DocComponent(PdfDocumen } @action onKeyDown = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = true); @action onKeyUp = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = false); + onContextMenu = (e: React.MouseEvent): void => { + let field = Cast(this.Document[this.props.fieldKey], PdfField); + if (field) { + let url = field.url.href; + ContextMenu.Instance.addItem({ + description: "Copy path", event: () => { + Utils.CopyText(url); + }, icon: "expand-arrows-alt" + }); + } + } render() { let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : ""); return ( -
+
{this.pdfRenderer}
); diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 6ae55d151..ab57b4b04 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -88,10 +88,14 @@ export class VideoBox extends DocComponent(VideoD if (vref) { vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen); if (this._reactionDisposer) this._reactionDisposer(); - this._reactionDisposer = reaction(() => this.props.Document.curPage, () => - vref.currentTime = NumCast(this.props.Document.curPage, 0), { fireImmediately: true }); + this._reactionDisposer = reaction(() => this.props.Document.curPage, () => { + if (!this.Playing) { + vref.currentTime = NumCast(this.props.Document.curPage, 0); + } + }, { fireImmediately: true }); } } + videoContent(path: string) { let style = "videoBox-cont" + (this._fullScreen ? "-fullScreen" : ""); return