From 02548014bc2a4a6a127147657599122e69ba60d6 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 18 Apr 2020 19:14:52 -0400 Subject: simplified startup icons to ones we actually use. moved ink icon to bottom bar. made webboxes default to enter title --- .../authentication/models/current_user_utils.ts | 42 ++++++++++++---------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'src/server/authentication/models/current_user_utils.ts') diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 9235a97b0..32cce9608 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -70,24 +70,24 @@ export class CurrentUserUtils { const emptyCollection = Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" }); doc.activePen = doc; const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ - { title: "collection", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: emptyCollection }, - { title: "preview", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' }, - { title: "web page", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("https://en.wikipedia.org/wiki/Hedgehog", {_width: 300, _height: 300, title: "New Webpage" })' }, - { title: "cat image", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth:250, title: "an image of a cat" })' }, - { title: "screenshot", icon: "photo-video", ignoreClick: true, drag: 'Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" })' }, - { title: "webcam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' }, - { title: "record", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, - { title: "clickable button", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' }, - { title: "presentation", icon: "tv", click: 'openOnRight(Doc.UserDoc().curPresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().curPresentation = getCopy(this.dragFactory,true)`, dragFactory: emptyPresentation }, - { title: "script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' }, - { title: "import folder", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, - { title: "mobile view", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, - { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, - { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, - { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, - { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc }, - { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc }, - { title: "query", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, + { title: "Drag a collection", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: emptyCollection }, + { title: "Drag a web page", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("", {_width: 300, _height: 300, title: "New Webpage" })' }, + { title: "Drag a cat image", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth:250, title: "an image of a cat" })' }, + { title: "Drag a screenshot", icon: "photo-video", ignoreClick: true, drag: 'Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" })' }, + { title: "Drag a webcam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' }, + { title: "Drag a audio recorder", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, + { title: "Drag a clickabl button", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' }, + { title: "Drag a presentation view", icon: "tv", click: 'openOnRight(Doc.UserDoc().curPresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().curPresentation = getCopy(this.dragFactory,true)`, dragFactory: emptyPresentation }, + { title: "Drag a scripting box", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' }, + { title: "Drag an import folder", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, + { title: "Drag a mobile view", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, + // { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, + // { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, + // { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, + // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc }, + // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc }, + { title: "Drag a search box", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, + { title: "Drag a document previewer", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' }, // { title: "buxton", icon: "cloud-upload-alt", ignoreClick: true, drag: "Docs.Create.Buxton()" }, ]; return docProtoData.filter(d => !alreadyCreatedButtons?.includes(d.title)).map(data => Docs.Create.FontIconDocument({ @@ -310,13 +310,17 @@ export class CurrentUserUtils { backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true })) as any as Doc; + doc.penBtn = ficon({ + onClick: ScriptField.MakeScript("activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)"), + title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.pen, this)`), activePen: doc + }) doc.undoBtn = ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" }); doc.redoBtn = ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" }); doc.slidesBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "sticky-note" }); doc.descriptionBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: descriptionTemplate, removeDropProperties: new List(["dropAction"]), title: "description view", icon: "sticky-note" }); doc.queryBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: queryTemplate, removeDropProperties: new List(["dropAction"]), title: "query view", icon: "sticky-note" }); doc.templateButtons = blist({ title: "template buttons", ignoreClick: true }, [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc]); - doc.expandingButtons = blist({ title: "expanding buttons", ignoreClick: true }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.templateButtons as Doc]); + doc.expandingButtons = blist({ title: "expanding buttons", ignoreClick: true }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.penBtn as Doc, doc.templateButtons as Doc]); doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as Doc, doc.templateButtons as Doc, doc.clickFuncs as Doc], { title: "template layouts", _xPadding: 0, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) -- cgit v1.2.3-70-g09d2 From b7c1c6890c9186578ce06e8c31cdd82662d1c934 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 18 Apr 2020 23:25:15 -0400 Subject: changed structure of template docs in sidebar. got rid of special context menu in tree view in favor of pushing everything to document context menus which ca now be extended by the local document or through props. --- src/client/documents/Documents.ts | 1 + src/client/util/DocumentManager.ts | 2 +- src/client/views/MainView.scss | 2 + src/client/views/MainView.tsx | 15 +- .../views/collections/CollectionStackingView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 46 ++---- src/client/views/nodes/DocumentView.scss | 1 - src/client/views/nodes/DocumentView.tsx | 26 ++-- .../authentication/models/current_user_utils.ts | 159 ++++++++++++--------- 9 files changed, 136 insertions(+), 118 deletions(-) (limited to 'src/server/authentication/models/current_user_utils.ts') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 3ac823bb0..3073707a6 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -79,6 +79,7 @@ export interface DocumentOptions { x?: number; y?: number; z?: number; + author?: string; dropAction?: dropActionType; childDropAction?: dropActionType; layoutKey?: string; diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index e66e67723..4683e77a8 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -241,4 +241,4 @@ export class DocumentManager { } } } -Scripting.addGlobal(function focus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)); }); \ No newline at end of file +Scripting.addGlobal(function DocFocus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)); }); \ No newline at end of file diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index e9f2248ad..81d427f64 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -5,6 +5,7 @@ .mainView-tabButtons { position: relative; width: 100%; + margin-top: 10px; } .mainContent-div { @@ -72,6 +73,7 @@ flex-direction: column; position: relative; height: 100%; + background: dimgray; .documentView-node-topmost { background: lightgrey; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index aec1f960a..40cabcf83 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faTerminal, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons'; +import { faTerminal, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -41,11 +41,12 @@ import { RadialMenu } from './nodes/RadialMenu'; import { OverlayView } from './OverlayView'; import PDFMenu from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; +import { ScriptField } from '../../new_fields/ScriptField'; @observer export class MainView extends React.Component { public static Instance: MainView; - private _buttonBarHeight = 35; + private _buttonBarHeight = 26; private _flyoutSizeOnDown = 0; private _urlState: HistoryUtil.DocUrl; private _docBtnRef = React.createRef(); @@ -102,7 +103,10 @@ export class MainView extends React.Component { } library.add(faTerminal); + library.add(faWindowMaximize); library.add(faFileAlt); + library.add(faAddressCard); + library.add(faQuestionCircle); library.add(faStickyNote); library.add(faFont); library.add(faExclamation); @@ -212,6 +216,11 @@ export class MainView extends React.Component { const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); Doc.AddDocToList(Doc.GetProto(CurrentUserUtils.UserDocument.documents as Doc), "data", freeformDoc); const mainDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().documents as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row"); + + const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`); + mainDoc.contextMenuScripts = new List([toggleTheme!]); + mainDoc.contextMenuLabels = new List(["Toggle Theme Colors"]); + Doc.AddDocToList(workspaces, "data", mainDoc); // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) setTimeout(() => this.openWorkspace(mainDoc), 0); @@ -459,7 +468,7 @@ export class MainView extends React.Component { } @computed get mainContent() { - const sidebar = this.userDoc && this.userDoc.sidebarContainer; + const sidebar = this.userDoc?.sidebarContainer; return !this.userDoc || !(sidebar instanceof Doc) ? (null) : (
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index dd84c4d6e..b15649d83 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -63,7 +63,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { const dxf = () => this.getDocTransform(d, dref.current!); this._docXfs.push({ dxf: dxf, width: width, height: height }); const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap); - const style = this.isStackingView ? { width: width(), marginTop: this.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` }; + const style = this.isStackingView ? { width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` }; return
{this.getDisplayDoc(d, (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc, dxf, width)}
; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 5ff8c11ee..2df1614de 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -32,7 +32,7 @@ import { Templates } from '../Templates'; import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import React = require("react"); -import { CollectionViewType } from './CollectionView'; +import { CollectionViewType, CollectionView } from './CollectionView'; import { RichTextField } from '../../../new_fields/RichTextField'; import { DocumentView } from '../nodes/DocumentView'; @@ -210,33 +210,6 @@ class TreeView extends React.Component { })} />) - onWorkspaceContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view - const sort = this.props.document[`${this.fieldKey}-sortAscending`]; - if (this.props.document === CurrentUserUtils.UserDocument.recentlyClosed) { - ContextMenu.Instance.addItem({ description: "Clear All", event: () => Doc.GetProto(CurrentUserUtils.UserDocument.recentlyClosed as Doc).data = new List(), icon: "plus" }); - } else if (this.props.document !== CurrentUserUtils.UserDocument.workspaces) { - ContextMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.document), icon: "tv" }); - ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, "inTab", this.props.libraryPath), icon: "folder" }); - ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, "onRight", this.props.libraryPath), icon: "caret-square-right" }); - if (DocumentManager.Instance.getDocumentViews(this.dataDoc).length) { - ContextMenu.Instance.addItem({ description: "Focus", event: () => (view => view && view.props.focus(this.props.document, true))(DocumentManager.Instance.getFirstDocumentView(this.props.document)), icon: "camera" }); - } - ContextMenu.Instance.addItem({ description: "Delete Item", event: () => this.props.deleteDoc(this.props.document), icon: "trash-alt" }); - } else { - ContextMenu.Instance.addItem({ description: "Delete Workspace", event: () => this.props.deleteDoc(this.props.document), icon: "trash-alt" }); - ContextMenu.Instance.addItem({ description: "Create New Workspace", event: () => MainView.Instance.createNewWorkspace(), icon: "plus" }); - } - ContextMenu.Instance.addItem({ description: (sort ? "Sort Descending" : (sort === false ? "Unsort" : "Sort Ascending")), event: () => this.props.document[`${this.fieldKey}-sortAscending`] = (sort ? false : (sort === false ? undefined : true)), icon: "minus" }); - ContextMenu.Instance.addItem({ description: "Toggle Theme Colors", event: () => this.props.document.darkScheme = !this.props.document.darkScheme, icon: "minus" }); - ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { const kvp = Docs.Create.KVPDocument(this.props.document, { _width: 300, _height: 300 }); this.props.addDocTab(kvp, "onRight"); }, icon: "layer-group" }); - ContextMenu.Instance.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.document, StrCast(this.props.document.title), () => { }, () => { }), icon: "file" }); - ContextMenu.Instance.displayMenu(e.pageX > 156 ? e.pageX - 156 : 0, e.pageY - 15); - e.stopPropagation(); - e.preventDefault(); - } - } - @undoBatch treeDrop = (e: Event, de: DragManager.DropEvent) => { const pt = [de.x, de.y]; @@ -356,7 +329,11 @@ class TreeView extends React.Component { const remDoc = (doc: Doc) => this.remove(doc, expandKey); const addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true); const docs = expandKey === "links" ? this.childLinks : this.childDocs; - return
    + const sortKey = `${this.fieldKey}-sortAscending`; + return
      { + this.props.document[sortKey] = (this.props.document[sortKey] ? false : (this.props.document[sortKey] === false ? undefined : true)); + e.stopPropagation(); + }}> {!docs ? (null) : TreeView.GetChildElements(docs, this.props.treeViewId, Doc.Layout(this.props.document), this.templateDataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, @@ -421,6 +398,12 @@ class TreeView extends React.Component { {}
; } + + focusOnDoc = (doc: Doc) => DocumentManager.Instance.getFirstDocumentView(doc)?.props.focus(doc, true); + contextMenuItems = () => { + const focusScript = ScriptField.MakeFunction(`DocFocus(self)`); + return [{ script: focusScript!, label: "Focus" }]; + } /** * Renders the EditableView title element for placement into the tree. */ @@ -442,7 +425,7 @@ class TreeView extends React.Component { })}> {this.treeViewExpandedView} ); - const openRight = (
+ const openRight = (
); return <> @@ -474,6 +457,7 @@ class TreeView extends React.Component { PanelHeight={returnZero} NativeHeight={returnZero} NativeWidth={returnZero} + contextMenuItems={this.contextMenuItems} renderDepth={1} focus={emptyFunction} parentActive={returnTrue} @@ -491,7 +475,7 @@ class TreeView extends React.Component { render() { setTimeout(() => runInAction(() => untracked(() => this._overrideTreeViewOpen = this.treeViewOpen)), 0); - return
+ return
  • {this.renderBullet} diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 81ae36cc0..692493414 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -71,7 +71,6 @@ display: inline-block; width: 100%; height: 100%; - pointer-events: none; .documentView-styleContentWrapper { width: 100%; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e3013698d..12f5b27e1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,21 +1,24 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import * as fa from '@fortawesome/free-solid-svg-icons'; -import { action, computed, runInAction, trace, observable } from "mobx"; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as rp from "request-promise"; -import { Doc, DocListCast, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc"; +import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; import { Document, PositionDocument } from '../../../new_fields/documentSchemas'; import { Id } from '../../../new_fields/FieldSymbols'; import { InkTool } from '../../../new_fields/InkField'; import { RichTextField } from '../../../new_fields/RichTextField'; import { listSpec } from "../../../new_fields/Schema"; +import { SchemaHeaderField } from '../../../new_fields/SchemaHeaderField'; import { ScriptField } from '../../../new_fields/ScriptField'; import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { AudioField, ImageField, PdfField, VideoField } from '../../../new_fields/URLField'; import { TraceMobx } from '../../../new_fields/util'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; -import { emptyFunction, returnOne, returnTransparent, returnTrue, Utils, OmitKeys, returnZero } from "../../../Utils"; +import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils } from "../../../Utils"; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; +import { ClientRecommender } from '../../ClientRecommender'; import { DocServer } from "../../DocServer"; import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents"; import { DocumentType } from '../../documents/DocumentTypes'; @@ -24,6 +27,7 @@ import { DocumentManager } from "../../util/DocumentManager"; import { DragManager, dropActionType } from "../../util/DragManager"; import { InteractionUtils } from '../../util/InteractionUtils'; import { Scripting } from '../../util/Scripting'; +import { SearchUtil } from '../../util/SearchUtil'; import { SelectionManager } from "../../util/SelectionManager"; import SharingManager from '../../util/SharingManager'; import { Transform } from "../../util/Transform"; @@ -35,19 +39,13 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { DocComponent } from "../DocComponent"; import { EditableView } from '../EditableView'; import { InkingControl } from '../InkingControl'; +import { KeyphraseQueryView } from '../KeyphraseQueryView'; import { OverlayView } from '../OverlayView'; -import { ScriptBox } from '../ScriptBox'; import { ScriptingRepl } from '../ScriptingRepl'; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; -import React = require("react"); -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { SchemaHeaderField } from '../../../new_fields/SchemaHeaderField'; -import { ClientRecommender } from '../../ClientRecommender'; -import { SearchUtil } from '../../util/SearchUtil'; import { RadialMenu } from './RadialMenu'; -import { KeyphraseQueryView } from '../KeyphraseQueryView'; -import { undo } from 'prosemirror-history'; +import React = require("react"); library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight, fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale, @@ -65,6 +63,7 @@ export interface DocumentViewProps { LayoutDoc?: () => Opt; LibraryPath: Doc[]; fitToBox?: boolean; + contextMenuItems?: () => { script: ScriptField, label: string }[]; rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected onClick?: ScriptField; onPointerDown?: ScriptField; @@ -720,6 +719,11 @@ export class DocumentView extends DocComponent(Docu const cm = ContextMenu.Instance; const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layoutKey)], Doc, null); + const customScripts = Cast(this.props.Document.contextMenuScripts, listSpec(ScriptField), []); + Cast(this.props.Document.contextMenuLabels, listSpec("string"), []).forEach((label, i) => + cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ this: this.layoutDoc, self: this.rootDoc }), icon: "sticky-note" })); + this.props.contextMenuItems?.().forEach(item => + cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.layoutDoc, self: this.rootDoc }), icon: "sticky-note" })); const existing = cm.findByDescription("Layout..."); const layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : []; layoutItems.push({ description: this.Document.isBackground ? "As Foreground" : "As Background", event: (e) => this.toggleBackground(false), icon: this.Document.lockedPosition ? "unlock" : "lock" }); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 32cce9608..e7a163a3e 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -18,6 +18,7 @@ import { makeTemplate } from "../../../client/util/DropConverter"; import { RichTextField } from "../../../new_fields/RichTextField"; import { PrefetchProxy } from "../../../new_fields/Proxy"; import { FormattedTextBox } from "../../../client/views/nodes/FormattedTextBox"; +import { MainView } from "../../../client/views/MainView"; export class CurrentUserUtils { private static curr_id: string; @@ -51,7 +52,17 @@ export class CurrentUserUtils { ]; doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" }); Doc.addFieldEnumerations(Doc.GetProto(noteTemplates[4]), "taskStatus", taskStatusValues); - doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Layouts", _height: 75 })); + doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Layouts", _height: 75 })) + doc.templateButtons = Docs.Create.MasonryDocument(CurrentUserUtils.setupTemplateButtons(doc), { + title: "template buttons", + _pivotField: "author", _xMargin: 0, + _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), + }); + doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as any as Doc, doc.templateButtons as Doc, doc.clickFuncs as Doc], { + title: "template layouts", _xPadding: 0, + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) + })); } static setupDefaultIconTypes(doc: Doc, buttons?: string[]) { doc.iconView = new PrefetchProxy(Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") })); @@ -86,7 +97,7 @@ export class CurrentUserUtils { // { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc }, // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc }, - { title: "Drag a search box", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, + { title: "Drag a search box", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, { title: "Drag a document previewer", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' }, // { title: "buxton", icon: "cloud-upload-alt", ignoreClick: true, drag: "Docs.Create.Buxton()" }, ]; @@ -94,6 +105,7 @@ export class CurrentUserUtils { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, icon: data.icon, title: data.title, + author: "Draggable Items", ignoreClick: data.ignoreClick, dropAction: data.click ? "copy" : undefined, onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, @@ -105,22 +117,40 @@ export class CurrentUserUtils { })); } + static setupTemplateButtons(doc: Doc) { + const queryTemplate = Docs.Create.MulticolumnDocument( + [ + Docs.Create.QueryDocument({ title: "query", _height: 200, forceActive: true }), + Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true, forceActive: true }) + ], + { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true }); + queryTemplate.isTemplateDoc = makeTemplate(queryTemplate); + const slideTemplate = Docs.Create.MultirowDocument( + [ + Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, forceActive: true }), + Docs.Create.TextDocument("", { title: "text", _height: 100, forceActive: true }) + ], + { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true }); + slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); + const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" }); + Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description"); + descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); + + doc.slidesBtn = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, author: "-Template Items", removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "address-card" }); + doc.descriptionBtn = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: descriptionTemplate, author: "-Template Items", removeDropProperties: new List(["dropAction"]), title: "description view", icon: "window-maximize" }); + doc.queryBtn = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: queryTemplate, author: "-Template Items", removeDropProperties: new List(["dropAction"]), title: "query view", icon: "question-circle" }); + + return [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc]; + } + + static async updateCreatorButtons(doc: Doc) { - const toolsBtn = await Cast(doc.ToolsBtn, Doc); - if (toolsBtn) { - const stackingDoc = await Cast(toolsBtn.sourcePanel, Doc); - if (stackingDoc) { - const stackdocs = await Cast(stackingDoc.data, listSpec(Doc)); - if (stackdocs) { - const dragset = await Cast(stackdocs[0], Doc); - if (dragset) { - const dragdocs = await Cast(dragset.data, listSpec(Doc)); - if (dragdocs) { - const dragDocs = await Promise.all(dragdocs); - this.setupCreatorButtons(doc, dragDocs.map(d => StrCast(d.title))).map(nb => Doc.AddDocToList(dragset, "data", nb)); - } - } - } + const dragset = await Cast(doc.dragCreators, Doc); + if (dragset) { + const dragdocs = await Cast(dragset.data, listSpec(Doc)); + if (dragdocs) { + const dragDocs = await Promise.all(dragdocs); + this.setupCreatorButtons(doc, dragDocs.map(d => StrCast(d.title))).map(nb => Doc.AddDocToList(dragset, "data", nb)); } } } @@ -203,9 +233,16 @@ export class CurrentUserUtils { // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker. when clicked, this panel will be displayed in the target container (ie, sidebarContainer) static setupToolsPanel(sidebarContainer: Doc, doc: Doc) { // setup a masonry view of all he creators - const dragCreators = Docs.Create.MasonryDocument(CurrentUserUtils.setupCreatorButtons(doc), { - _width: 500, _autoHeight: true, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), _yMargin: 5 + const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc); + doc.dragCreators = Docs.Create.MasonryDocument(creatorBtns, { + title: "drag Creators", + _pivotField: "author", _xMargin: 0, + _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), + }); + doc.allCreators = Docs.Create.StackingDocument([doc.dragCreators as any as Doc, doc.templateButtons as any as Doc], { + title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0, + _width: 500, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", }); // setup a color picker const color = Docs.Create.ColorDocument({ @@ -215,7 +252,7 @@ export class CurrentUserUtils { return Docs.Create.ButtonDocument({ _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer, letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", - sourcePanel: Docs.Create.StackingDocument([dragCreators, color], { + sourcePanel: Docs.Create.StackingDocument([doc.allCreators as Doc, color], { _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true }), onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"), @@ -228,6 +265,9 @@ export class CurrentUserUtils { doc.workspaces = Docs.Create.TreeDocument([], { title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true, }); + const newWorkspace = ScriptField.MakeScript(`createNewWorkspace()`); + (doc.workspaces as Doc).contextMenuScripts = new List([newWorkspace!]); + (doc.workspaces as Doc).contextMenuLabels = new List(["Create New Workspace"]); doc.documents = Docs.Create.TreeDocument([], { title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, @@ -237,11 +277,14 @@ export class CurrentUserUtils { doc.recentlyClosed = Docs.Create.TreeDocument([], { title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, }); + const clearAll = ScriptField.MakeScript(`self.data = new List([])`); + (doc.recentlyClosed as Doc).contextMenuScripts = new List([clearAll!]); + (doc.recentlyClosed as Doc).contextMenuLabels = new List(["Clear All"]); return Docs.Create.ButtonDocument({ _width: 50, _height: 25, title: "Library", fontSize: 10, letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", - sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc, doc.recentlyClosed as Doc], { + sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, doc.recentlyClosed as Doc, doc], { title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "place", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true }), targetContainer: sidebarContainer, @@ -279,54 +322,28 @@ export class CurrentUserUtils { })); } - /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window - static setupExpandingButtons(doc: Doc) { - const queryTemplate = Docs.Create.MulticolumnDocument( - [ - Docs.Create.QueryDocument({ title: "query", _height: 200, forceActive: true }), - Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true, forceActive: true }) - ], - { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true }); - queryTemplate.isTemplateDoc = makeTemplate(queryTemplate); - const slideTemplate = Docs.Create.MultirowDocument( - [ - Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, forceActive: true }), - Docs.Create.TextDocument("", { title: "text", _height: 100, forceActive: true }) - ], - { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true }); - slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); - const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" }); - Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description"); - descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); + static blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, { + ...opts, + _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", forceActive: true, + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), + backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true + })) as any as Doc; - const ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ - ...opts, - dropAction: "alias", removeDropProperties: new List(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 - })) as any as Doc; - const blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, { - ...opts, - _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", forceActive: true, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), - backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true - })) as any as Doc; + static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ + ...opts, + dropAction: "alias", removeDropProperties: new List(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 + })) as any as Doc; - doc.penBtn = ficon({ + /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window + static setupExpandingButtons(doc: Doc) { + doc.penBtn = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)"), - title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.pen, this)`), activePen: doc + author: "systemTemplates", title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.pen, this)`), activePen: doc }) - doc.undoBtn = ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" }); - doc.redoBtn = ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" }); - doc.slidesBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "sticky-note" }); - doc.descriptionBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: descriptionTemplate, removeDropProperties: new List(["dropAction"]), title: "description view", icon: "sticky-note" }); - doc.queryBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: queryTemplate, removeDropProperties: new List(["dropAction"]), title: "query view", icon: "sticky-note" }); - doc.templateButtons = blist({ title: "template buttons", ignoreClick: true }, [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc]); - doc.expandingButtons = blist({ title: "expanding buttons", ignoreClick: true }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.penBtn as Doc, doc.templateButtons as Doc]); - doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as Doc, doc.templateButtons as Doc, doc.clickFuncs as Doc], { - title: "template layouts", _xPadding: 0, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) - })); + doc.undoBtn = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" }); + doc.redoBtn = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" }); + doc.expandingButtons = CurrentUserUtils.blist({ title: "expanding buttons", ignoreClick: true }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.penBtn as Doc]); } - // sets up the default set of documents to be shown in the Overlay layer static setupOverlays(doc: Doc) { doc.overlays = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "Overlays", backgroundColor: "#aca3a6" })); @@ -356,14 +373,15 @@ export class CurrentUserUtils { static updateUserDocument(doc: Doc) { doc.title = Doc.CurrentUserEmail; new InkingControl(); - (doc.iconTypes === undefined) && CurrentUserUtils.setupDefaultIconTypes(doc); - (doc.noteTypes === undefined) && CurrentUserUtils.setupDefaultDocTemplates(doc); (doc.childClickFuncs === undefined) && CurrentUserUtils.setupChildClicks(doc); + (doc.iconTypes === undefined) && CurrentUserUtils.setupDefaultIconTypes(doc); + (doc.templateDocs === undefined) && CurrentUserUtils.setupDefaultDocTemplates(doc); (doc.optionalRightCollection === undefined) && CurrentUserUtils.setupMobileUploads(doc); (doc.overlays === undefined) && CurrentUserUtils.setupOverlays(doc); (doc.expandingButtons === undefined) && CurrentUserUtils.setupExpandingButtons(doc); (doc.curPresentation === undefined) && CurrentUserUtils.setupDefaultPresentation(doc); (doc.sidebarButtons === undefined) && CurrentUserUtils.setupSidebarButtons(doc); + doc.linkDb = Docs.Prototypes.MainLinkDocument(); // this is equivalent to using PrefetchProxies to make sure all the childClickFuncs have been retrieved. PromiseValue(Cast(doc.childClickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); @@ -375,9 +393,9 @@ export class CurrentUserUtils { PromiseValue(Cast(doc.childClickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); PromiseValue(Cast(doc.sidebarButtons, Doc)).then(stackingDoc => { stackingDoc && PromiseValue(Cast(stackingDoc.data, listSpec(Doc))).then(sidebarButtons => { - sidebarButtons && sidebarButtons.map((sidebarBtn, i) => { - sidebarBtn && PromiseValue(Cast(sidebarBtn, Doc)).then(async btn => { - btn && btn.sourcePanel && btn.targetContainer && i === 1 && (btn.onClick as ScriptField).script.run({ this: btn }); + sidebarButtons?.map((sidebarBtn, i) => { + sidebarBtn && PromiseValue(Cast(sidebarBtn, Doc)).then(async btn => { // choose which item to display first in sidebar panel (i === 0,1, or 2) + btn?.sourcePanel && btn.targetContainer && i === 2 && (btn.onClick as ScriptField).script.run({ this: btn }); }); }); }); @@ -427,3 +445,4 @@ export class CurrentUserUtils { Scripting.addGlobal(function setupMobileInkingDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileInkingDoc(userDoc); }); Scripting.addGlobal(function setupMobileUploadDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileUploadDoc(userDoc); }); +Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.createNewWorkspace(); }); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From ea359c9d247a9be59b78ed043be6427ab10cb8bd Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 19 Apr 2020 01:40:54 -0400 Subject: added optional labels for font icons. --- src/client/documents/Documents.ts | 1 + .../views/collections/CollectionTreeView.tsx | 8 +++++- src/client/views/nodes/DocumentView.tsx | 4 ++- src/client/views/nodes/FontIconBox.scss | 12 +++++++++ src/client/views/nodes/FontIconBox.tsx | 1 + .../authentication/models/current_user_utils.ts | 29 +++++++++++----------- 6 files changed, 39 insertions(+), 16 deletions(-) (limited to 'src/server/authentication/models/current_user_utils.ts') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 3073707a6..209a72d52 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -85,6 +85,7 @@ export interface DocumentOptions { layoutKey?: string; type?: string; title?: string; + label?: string; // short form of title for use as an icon label style?: string; page?: number; scale?: number; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index c2838a15e..cd1e23bbd 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -483,7 +483,13 @@ class TreeView extends React.Component { setTimeout(() => runInAction(() => untracked(() => this._overrideTreeViewOpen = this.treeViewOpen)), 0); return
  • -
    +
    { + e.stopPropagation(); + e.preventDefault(); + }} onPointerDown={e => { + e.stopPropagation(); + e.preventDefault(); + }} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}> {this.renderBullet} {this.renderTitle}
    diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d114698ea..d8178ea77 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1172,7 +1172,9 @@ export class DocumentView extends DocComponent(Docu
    : this.innards} - {(this.Document.isBackground !== undefined || this.isSelected(false)) && this.props.renderDepth > 0 ?
    this.toggleBackground(true)}>
    : (null)} + {(this.Document.isBackground !== undefined || this.isSelected(false)) && this.props.renderDepth > 0 && this.props.PanelWidth() > 0 ? +
    this.toggleBackground(true)}>
    + : (null)}
    ; { this._showKPQuery ? : undefined; } } diff --git a/src/client/views/nodes/FontIconBox.scss b/src/client/views/nodes/FontIconBox.scss index f0fe7a54e..68b00a5be 100644 --- a/src/client/views/nodes/FontIconBox.scss +++ b/src/client/views/nodes/FontIconBox.scss @@ -8,6 +8,18 @@ border-radius: 100%; transform-origin: top left; + .fontIconBox-label { + background: gray; + color:white; + margin-left: -10px; + border-radius: 8px; + width:100%; + position: absolute; + text-align: center; + font-size: 8px; + margin-top:4px; + } + svg { width: 95% !important; height: 95%; diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index 9329cf210..c6ea6a882 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -57,6 +57,7 @@ export class FontIconBox extends DocComponent( boxShadow: this.props.Document.ischecked ? `4px 4px 12px black` : undefined }}> + {!this.rootDoc.label ? (null) :
    {StrCast(this.rootDoc.label).substring(0, 5)}
    } ; } } \ No newline at end of file diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index e7a163a3e..7e5f7257a 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -80,31 +80,32 @@ export class CurrentUserUtils { const emptyPresentation = Docs.Create.PresDocument(new List(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" }); const emptyCollection = Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" }); doc.activePen = doc; - const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ - { title: "Drag a collection", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: emptyCollection }, - { title: "Drag a web page", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("", {_width: 300, _height: 300, title: "New Webpage" })' }, - { title: "Drag a cat image", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth:250, title: "an image of a cat" })' }, - { title: "Drag a screenshot", icon: "photo-video", ignoreClick: true, drag: 'Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" })' }, - { title: "Drag a webcam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' }, - { title: "Drag a audio recorder", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, - { title: "Drag a clickabl button", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' }, - { title: "Drag a presentation view", icon: "tv", click: 'openOnRight(Doc.UserDoc().curPresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().curPresentation = getCopy(this.dragFactory,true)`, dragFactory: emptyPresentation }, - { title: "Drag a scripting box", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' }, - { title: "Drag an import folder", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, - { title: "Drag a mobile view", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, + const docProtoData: { title: string, label: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ + { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: emptyCollection }, + { title: "Drag a web page", label: "Web", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("", {_width: 300, _height: 300, title: "New Webpage" })' }, + { title: "Drag a cat image", label: "Img", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth:250, title: "an image of a cat" })' }, + { title: "Drag a screenshot", label: "Grab", icon: "photo-video", ignoreClick: true, drag: 'Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" })' }, + { title: "Drag a webcam", label: "Cam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' }, + { title: "Drag a audio recorder", label: "Audio", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, + { title: "Drag a clickable button", label: "Btn", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' }, + { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().curPresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().curPresentation = getCopy(this.dragFactory,true)`, dragFactory: emptyPresentation }, + { title: "Drag a scripting box", label: "Script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' }, + { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, + { title: "Drag a mobile view", label: "Phone", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, // { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, // { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, // { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc }, // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc }, - { title: "Drag a search box", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, - { title: "Drag a document previewer", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' }, + { title: "Drag a search box", label: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, + { title: "Drag a document previewer", label: "Prev", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' }, // { title: "buxton", icon: "cloud-upload-alt", ignoreClick: true, drag: "Docs.Create.Buxton()" }, ]; return docProtoData.filter(d => !alreadyCreatedButtons?.includes(d.title)).map(data => Docs.Create.FontIconDocument({ _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, icon: data.icon, title: data.title, + label: data.label, author: "Draggable Items", ignoreClick: data.ignoreClick, dropAction: data.click ? "copy" : undefined, -- cgit v1.2.3-70-g09d2 From bdf4ac9601e54bf8e2a3a8f988c97274d84ae8a4 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 19 Apr 2020 13:30:20 -0400 Subject: fixed removing docs from tree view with menu. restructured current_user_utils completely --- src/client/views/MainView.tsx | 11 +- .../views/collections/CollectionTreeView.tsx | 6 +- src/client/views/nodes/AudioBox.tsx | 5 +- src/client/views/nodes/DocumentView.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 4 +- src/client/views/pdf/PDFViewer.tsx | 2 +- .../authentication/models/current_user_utils.ts | 562 +++++++++++++-------- src/server/database.ts | 3 - 8 files changed, 369 insertions(+), 230 deletions(-) (limited to 'src/server/authentication/models/current_user_utils.ts') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 40cabcf83..0877cc5f6 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -61,7 +61,7 @@ export class MainView extends React.Component { @computed private get userDoc() { return Doc.UserDoc(); } @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeWorkspace, Doc)) : CurrentUserUtils.GuestWorkspace; } @computed public get mainFreeform(): Opt { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); } - @computed public get sidebarButtonsDoc() { return Cast(CurrentUserUtils.UserDocument.sidebarButtons, Doc) as Doc; } + @computed public get sidebarButtonsDoc() { return Cast(this.userDoc["tabs-buttons"], Doc) as Doc; } public isPointerDown = false; @@ -399,15 +399,14 @@ export class MainView extends React.Component { mainContainerXf = () => new Transform(0, -this._buttonBarHeight, 1); @computed get flyout() { - const sidebarContent = this.userDoc?.sidebarContainer; + const sidebarContent = this.userDoc?.["tabs-panelContainer"]; if (!(sidebarContent instanceof Doc)) { return (null); } - const sidebarButtonsDoc = Cast(CurrentUserUtils.UserDocument.sidebarButtons, Doc) as Doc; return
    -
    +
    diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index cd1e23bbd..c243d8f29 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -139,6 +139,9 @@ class TreeView extends React.Component { @undoBatch @action remove = (document: Document, key: string) => { return Doc.RemoveDocFromList(this.dataDoc, key, document); } + @undoBatch @action removeDoc = (document: Document) => { + return Doc.RemoveDocFromList(this.props.containingCollection, Doc.LayoutFieldKey(this.props.containingCollection), document); + } protected createTreeDropTarget = (ele: HTMLDivElement) => { this._treedropDisposer && this._treedropDisposer(); @@ -455,7 +458,7 @@ class TreeView extends React.Component { onClick={this.props.onChildClick || editTitle} dropAction={this.props.dropAction} moveDocument={this.props.moveDocument} - removeDocument={undefined} + removeDocument={this.removeDoc} ScreenToLocalTransform={this.getTransform} ContentScaling={returnOne} PanelWidth={returnZero} @@ -778,6 +781,7 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as } render() { + if (!(this.props.Document instanceof Doc)) return (null); const dropAction = StrCast(this.props.Document.childDropAction) as dropActionType; const addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before); const moveDoc = (d: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc); diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 7078cc01c..8f40ea2be 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -20,6 +20,7 @@ import { DocumentView } from "./DocumentView"; import { Docs } from "../../documents/Documents"; import { ComputedField } from "../../../new_fields/ScriptField"; import { Networking } from "../../Network"; +import { Upload } from "../../../server/SharedMediaTypes"; // testing testing @@ -146,7 +147,9 @@ export class AudioBox extends ViewBoxBaseComponent { const [{ result }] = await Networking.UploadFilesToServer(e.data); - this.props.Document[this.props.fieldKey] = new AudioField(Utils.prepend(result.accessPaths.agnostic.client)); + if (!(result instanceof Error)) { + this.props.Document[this.props.fieldKey] = new AudioField(Utils.prepend(result.accessPaths.agnostic.client)); + } }; this._recordStart = new Date().getTime(); runInAction(() => this.audioState = "recording"); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5c1326b1a..ca4ec7aff 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -560,14 +560,14 @@ export class DocumentView extends DocComponent(Docu } static findTemplate(templateName: string, type: string, signature: string) { let docLayoutTemplate: Opt; - const iconViews = DocListCast(Cast(Doc.UserDoc().iconViews, Doc, null)?.data); + const iconViews = DocListCast(Cast(Doc.UserDoc()["icon-view-all"], Doc, null)?.data); const templBtns = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data); const noteTypes = DocListCast(Cast(Doc.UserDoc().noteTypes, Doc, null)?.data); const clickFuncs = DocListCast(Cast(Doc.UserDoc().clickFuncs, Doc, null)?.data); const allTemplates = iconViews.concat(templBtns).concat(noteTypes).concat(clickFuncs).map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc); // bcz: this is hacky -- want to have different templates be applied depending on the "type" of a document. but type is not reliable and there could be other types of template searches so this should be generalized // first try to find a template that matches the specific document type (_). otherwise, fallback to a general match on - !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === type + "_" + templateName && (docLayoutTemplate = tempDoc)); + !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName + "_" + type && (docLayoutTemplate = tempDoc)); !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName && (docLayoutTemplate = tempDoc)); return docLayoutTemplate; } @@ -991,7 +991,7 @@ export class DocumentView extends DocComponent(Docu return typeof fallback === "string" ? fallback : "layout"; } rootSelected = (outsideReaction?: boolean) => { - return this.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)); + return this.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false; } childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling()); panelWidth = () => this.props.PanelWidth(); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 36907c4a7..66ddf64c9 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -68,7 +68,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { - const scroll = (e.target as any)?.children?.[0].scrollTop; + const scroll = e.target?.children?.[0].scrollTop; this.layoutDoc.scrollTop = this._outerRef.current!.scrollTop = scroll; } async componentDidMount() { @@ -345,7 +345,7 @@ export class WebBox extends ViewBoxAnnotatableComponent} ); } - scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.props.Document.scrollTop)) + scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.props.Document.scrollTop)); render() { return (
    { // creates annotation documents for current highlights const annotationDoc = this.makeAnnotationDocument(color); - annotationDoc && this.props?.addDocument(annotationDoc); + annotationDoc && this.props.addDocument?.(annotationDoc); return annotationDoc; } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 7e5f7257a..3d68d8425 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -19,6 +19,7 @@ import { RichTextField } from "../../../new_fields/RichTextField"; import { PrefetchProxy } from "../../../new_fields/Proxy"; import { FormattedTextBox } from "../../../client/views/nodes/FormattedTextBox"; import { MainView } from "../../../client/views/MainView"; +import { DocumentType } from "../../../client/documents/DocumentTypes"; export class CurrentUserUtils { private static curr_id: string; @@ -35,60 +36,151 @@ export class CurrentUserUtils { @observable public static GuestWorkspace: Doc | undefined; @observable public static GuestMobile: Doc | undefined; - static setupDefaultDocTemplates(doc: Doc, buttons?: string[]) { - const taskStatusValues = [{ title: "todo", _backgroundColor: "blue", color: "white" }, - { title: "in progress", _backgroundColor: "yellow", color: "black" }, - { title: "completed", _backgroundColor: "green", color: "white" } - ]; - const noteTemplates = [ - Docs.Create.TextDocument("", { title: "text", style: "Note", isTemplateDoc: true, backgroundColor: "yellow" }), - Docs.Create.TextDocument("", { title: "text", style: "Idea", isTemplateDoc: true, backgroundColor: "pink" }), - Docs.Create.TextDocument("", { title: "text", style: "Topic", isTemplateDoc: true, backgroundColor: "lightBlue" }), - Docs.Create.TextDocument("", { title: "text", style: "Person", isTemplateDoc: true, backgroundColor: "lightGreen" }), - Docs.Create.TextDocument("", { - title: "text", style: "Todo", isTemplateDoc: true, backgroundColor: "orange", _autoHeight: false, - layout: FormattedTextBox.LayoutString("Todo"), _height: 100, _showCaption: "caption", caption: RichTextField.DashField("taskStatus") - }) - ]; - doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" }); - Doc.addFieldEnumerations(Doc.GetProto(noteTemplates[4]), "taskStatus", taskStatusValues); - doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Layouts", _height: 75 })) - doc.templateButtons = Docs.Create.MasonryDocument(CurrentUserUtils.setupTemplateButtons(doc), { - title: "template buttons", - _pivotField: "author", _xMargin: 0, - _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), - }); - doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as any as Doc, doc.templateButtons as Doc, doc.clickFuncs as Doc], { - title: "template layouts", _xPadding: 0, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) - })); + // sets up the default User Templates - slideView, queryView, descriptionView + static setupUserTemplateButtons(doc: Doc) { + if (doc["template-button-query"] === undefined) { + const queryTemplate = Docs.Create.MulticolumnDocument( + [ + Docs.Create.QueryDocument({ title: "query", _height: 200 }), + Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true }) + ], + { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true } + ); + queryTemplate.isTemplateDoc = makeTemplate(queryTemplate); + doc["template-button-query"] = CurrentUserUtils.ficon({ + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, + removeDropProperties: new List(["dropAction"]), title: "query view", icon: "question-circle" + }); + } + + if (doc["template-button-slides"] === undefined) { + const slideTemplate = Docs.Create.MultirowDocument( + [ + Docs.Create.MulticolumnDocument([], { title: "data", _height: 200 }), + Docs.Create.TextDocument("", { title: "text", _height: 100 }) + ], + { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true } + ); + slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); + doc["template-button-slides"] = CurrentUserUtils.ficon({ + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, + removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "address-card" + }); + } + + if (doc["template-button-description"] === undefined) { + const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" }); + Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description"); + descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); + + doc["template-button-description"] = CurrentUserUtils.ficon({ + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + dragFactory: new PrefetchProxy(descriptionTemplate) as any as Doc, + removeDropProperties: new List(["dropAction"]), title: "description view", icon: "window-maximize" + }); + } + + if (doc["template-buttons"] === undefined) { + doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument([doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc, doc["template-button-query"] as Doc], { + title: "template buttons", _xMargin: 0, _showTitle: "title", + _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), + })); + } + return doc["template-buttons"] as Doc; } - static setupDefaultIconTypes(doc: Doc, buttons?: string[]) { - doc.iconView = new PrefetchProxy(Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") })); - Doc.GetProto(doc.iconView as any as Doc).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', ""); - doc.isTemplateDoc = makeTemplate(doc.iconView as any as Doc); - doc.iconImageView = new PrefetchProxy(Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { title: "data", _width: 50, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(self)") })); - doc.isTemplateDoc = makeTemplate(doc.iconImageView as any as Doc, true, "image_icon"); - doc.iconColView = new PrefetchProxy(Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(self)") })); - doc.isTemplateDoc = makeTemplate(doc.iconColView as any as Doc, true, "collection_icon"); - doc.iconViews = Docs.Create.TreeDocument([doc.iconView as any as Doc, doc.iconImageView as any as Doc, doc.iconColView as any as Doc], { title: "icon types", _height: 75 }); + + // setup the different note type skins + static setupNoteTemplates(doc: Doc) { + if (doc.noteTypes === undefined) { + const taskStatusValues = [ + { title: "todo", _backgroundColor: "blue", color: "white" }, + { title: "in progress", _backgroundColor: "yellow", color: "black" }, + { title: "completed", _backgroundColor: "green", color: "white" } + ]; + const noteTemplates = [ + Docs.Create.TextDocument("", { title: "text", style: "Note", isTemplateDoc: true, backgroundColor: "yellow" }), + Docs.Create.TextDocument("", { title: "text", style: "Idea", isTemplateDoc: true, backgroundColor: "pink" }), + Docs.Create.TextDocument("", { title: "text", style: "Topic", isTemplateDoc: true, backgroundColor: "lightBlue" }), + Docs.Create.TextDocument("", { title: "text", style: "Person", isTemplateDoc: true, backgroundColor: "lightGreen" }), + Docs.Create.TextDocument("", { + title: "text", style: "Todo", isTemplateDoc: true, backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption", + layout: FormattedTextBox.LayoutString("Todo"), caption: RichTextField.DashField("taskStatus") + }) + ]; + doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" }); + Doc.addFieldEnumerations(Doc.GetProto(noteTemplates[4]), "taskStatus", taskStatusValues); + doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), + { title: "Note Layouts", _height: 75 })); + } + // this is equivalent to using PrefetchProxies to make sure all the sidebarButtons and noteType internal Doc's have been retrieved. + PromiseValue(Cast(doc.noteTypes, Doc)).then(noteTypes => noteTypes && PromiseValue(noteTypes.data).then(DocListCast)); + return doc.noteTypes as Doc; } - // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools - static setupCreatorButtons(doc: Doc, alreadyCreatedButtons?: string[]) { - const emptyPresentation = Docs.Create.PresDocument(new List(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" }); - const emptyCollection = Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" }); - doc.activePen = doc; - const docProtoData: { title: string, label: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ - { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: emptyCollection }, - { title: "Drag a web page", label: "Web", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("", {_width: 300, _height: 300, title: "New Webpage" })' }, + // creates Note templates, and initial "user" templates + static setupDocTemplates(doc: Doc) { + const noteTemplates = CurrentUserUtils.setupNoteTemplates(doc); + const userTemplateBtns = CurrentUserUtils.setupUserTemplateButtons(doc); + const clickTemplates = CurrentUserUtils.setupClickEditorTemplates(doc); + if (doc.templateDocs === undefined) { + doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([noteTemplates, userTemplateBtns, clickTemplates], { + title: "template layouts", _xPadding: 0, + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) + })); + } + } + + // setup templates for different document types when they are iconified from Document Decorations + static setupDefaultIconTemplates(doc: Doc) { + if (doc["icon-view"] === undefined) { + const iconView = Docs.Create.TextDocument("", { + title: "icon", _width: 150, _height: 30, isTemplateDoc: true, + onClick: ScriptField.MakeScript("deiconifyView(this)") + }); + Doc.GetProto(iconView).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', ""); + iconView.isTemplateDoc = makeTemplate(iconView); + doc["icon-view"] = new PrefetchProxy(iconView); + } + if (doc["icon-view-img"] === undefined) { + const iconImageView = Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { title: "data", _width: 50, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(self)") }); + iconImageView.isTemplateDoc = makeTemplate(iconImageView, true, "icon_" + DocumentType.IMG); + doc["icon-view-img"] = new PrefetchProxy(iconImageView); + } + if (doc["icon-view-col"] === undefined) { + const iconColView = Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, onClick: ScriptField.MakeScript("deiconifyView(self)") }); + iconColView.isTemplateDoc = makeTemplate(iconColView, true, "icon_" + DocumentType.COL); + doc["icon-view-col"] = new PrefetchProxy(iconColView); + } + if (doc["icon-view-all"] === undefined) { + doc["icon-view-all"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["icon-view"] as Doc, doc["icon-view-img"] as Doc, doc["icon-view-col"] as Doc], { title: "icon templates", _height: 75 })); + } + return doc["icon-view-all"] as Doc; + } + + static creatorBtnDescriptors(doc: Doc): { + title: string, label: string, icon: string, drag?: string, ignoreClick?: boolean, + click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc + }[] { + if (doc.emptyPresentation === undefined) { + doc.emptyPresentation = Docs.Create.PresDocument(new List(), + { title: "Presentation", _viewType: CollectionViewType.Stacking, _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" }); + } + if (doc.emptyCollection === undefined) { + doc.emptyCollection = Docs.Create.FreeformDocument([], + { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" }); + } + return [ + { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc }, + { title: "Drag a web page", label: "Web", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("", { title: "New Webpage" })' }, { title: "Drag a cat image", label: "Img", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth:250, title: "an image of a cat" })' }, { title: "Drag a screenshot", label: "Grab", icon: "photo-video", ignoreClick: true, drag: 'Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" })' }, { title: "Drag a webcam", label: "Cam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' }, { title: "Drag a audio recorder", label: "Audio", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, { title: "Drag a clickable button", label: "Btn", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' }, - { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().curPresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().curPresentation = getCopy(this.dragFactory,true)`, dragFactory: emptyPresentation }, + { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().curPresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().curPresentation = getCopy(this.dragFactory,true)`, dragFactory: doc.emptyPresentation as Doc }, { title: "Drag a scripting box", label: "Script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' }, { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, { title: "Drag a mobile view", label: "Phone", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, @@ -101,59 +193,45 @@ export class CurrentUserUtils { { title: "Drag a document previewer", label: "Prev", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' }, // { title: "buxton", icon: "cloud-upload-alt", ignoreClick: true, drag: "Docs.Create.Buxton()" }, ]; - return docProtoData.filter(d => !alreadyCreatedButtons?.includes(d.title)).map(data => Docs.Create.FontIconDocument({ - _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, - icon: data.icon, - title: data.title, - label: data.label, - author: "Draggable Items", - ignoreClick: data.ignoreClick, - dropAction: data.click ? "copy" : undefined, - onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, - onClick: data.click ? ScriptField.MakeScript(data.click) : undefined, - ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, - activePen: data.activePen, - backgroundColor: data.backgroundColor, removeDropProperties: new List(["dropAction"]), - dragFactory: data.dragFactory, - })); - } - - static setupTemplateButtons(doc: Doc) { - const queryTemplate = Docs.Create.MulticolumnDocument( - [ - Docs.Create.QueryDocument({ title: "query", _height: 200, forceActive: true }), - Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true, forceActive: true }) - ], - { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true }); - queryTemplate.isTemplateDoc = makeTemplate(queryTemplate); - const slideTemplate = Docs.Create.MultirowDocument( - [ - Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, forceActive: true }), - Docs.Create.TextDocument("", { title: "text", _height: 100, forceActive: true }) - ], - { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true }); - slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); - const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" }); - Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description"); - descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); - - doc.slidesBtn = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, author: "-Template Items", removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "address-card" }); - doc.descriptionBtn = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: descriptionTemplate, author: "-Template Items", removeDropProperties: new List(["dropAction"]), title: "description view", icon: "window-maximize" }); - doc.queryBtn = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: queryTemplate, author: "-Template Items", removeDropProperties: new List(["dropAction"]), title: "query view", icon: "question-circle" }); - - return [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc]; } - - static async updateCreatorButtons(doc: Doc) { - const dragset = await Cast(doc.dragCreators, Doc); - if (dragset) { - const dragdocs = await Cast(dragset.data, listSpec(Doc)); - if (dragdocs) { - const dragDocs = await Promise.all(dragdocs); - this.setupCreatorButtons(doc, dragDocs.map(d => StrCast(d.title))).map(nb => Doc.AddDocToList(dragset, "data", nb)); + // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools + static async setupCreatorButtons(doc: Doc) { + let alreadyCreatedButtons: string[] = []; + const dragCreatorSet = await Cast(doc.dragCreators, Doc, null); + if (dragCreatorSet) { + const dragCreators = await Cast(dragCreatorSet.data, listSpec(Doc)); + if (dragCreators) { + const dragDocs = await Promise.all(dragCreators); + alreadyCreatedButtons = dragDocs.map(d => StrCast(d.title)); } } + const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title)). + map(data => Docs.Create.FontIconDocument({ + _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, + icon: data.icon, + title: data.title, + label: data.label, + ignoreClick: data.ignoreClick, + dropAction: data.click ? "copy" : undefined, + onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, + onClick: data.click ? ScriptField.MakeScript(data.click) : undefined, + ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, + activePen: data.activePen, + backgroundColor: data.backgroundColor, removeDropProperties: new List(["dropAction"]), + dragFactory: data.dragFactory, + })); + + if (dragCreatorSet === undefined) { + doc.dragCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, { + title: "Draggable Items", _showTitle: "title", _xMargin: 0, + _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), + })); + } else { + creatorBtns.forEach(nb => Doc.AddDocToList(doc.dragCreators as Doc, "data", nb)); + } + return doc.dragCreators as Doc; } static setupMobileButtons(doc: Doc, buttons?: string[]) { @@ -231,96 +309,138 @@ export class CurrentUserUtils { }); } - // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker. when clicked, this panel will be displayed in the target container (ie, sidebarContainer) - static setupToolsPanel(sidebarContainer: Doc, doc: Doc) { + // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker. + // when clicked, this panel will be displayed in the target container (ie, sidebarContainer) + static async setupToolsBtnPanel(doc: Doc, sidebarContainer: Doc) { // setup a masonry view of all he creators - const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc); - doc.dragCreators = Docs.Create.MasonryDocument(creatorBtns, { - title: "drag Creators", - _pivotField: "author", _xMargin: 0, - _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), - }); - doc.allCreators = Docs.Create.StackingDocument([doc.dragCreators as any as Doc, doc.templateButtons as any as Doc], { - title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0, - _width: 500, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", - }); + const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc); + const templateBtns = CurrentUserUtils.setupUserTemplateButtons(doc); + + if (doc.allCreators === undefined) { + doc.allCreators = new PrefetchProxy(Docs.Create.StackingDocument([creatorBtns, templateBtns], { + title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0, + _width: 500, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", + })); + } // setup a color picker - const color = Docs.Create.ColorDocument({ - title: "color picker", _width: 300, dropAction: "alias", forceActive: true, removeDropProperties: new List(["dropAction", "forceActive"]) - }); + if (doc.colorPicker === undefined) { + const color = Docs.Create.ColorDocument({ + title: "color picker", _width: 300, dropAction: "alias", forceActive: true, removeDropProperties: new List(["dropAction", "forceActive"]) + }); + doc.colorPicker = new PrefetchProxy(color); + } - return Docs.Create.ButtonDocument({ - _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer, - letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", - sourcePanel: Docs.Create.StackingDocument([doc.allCreators as Doc, color], { - _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true - }), - onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"), - }); + if (doc["tabs-button-tools"] === undefined) { + doc["tabs-button-tools"] = new PrefetchProxy(Docs.Create.ButtonDocument({ + _width: 35, _height: 25, title: "Tools", fontSize: 10, + letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", + sourcePanel: new PrefetchProxy(Docs.Create.StackingDocument([doc.allCreators as Doc, doc.colorPicker as Doc], { + _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true + })) as any as Doc, + targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, + onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"), + })); + } + (doc["tabs-button-tools"] as Doc).sourcePanel; // prefetch sourcePanel + return doc["tabs-button-tools"] as Doc; } - // setup the Library button which will display the library panel. This panel includes a collection of workspaces, documents, and recently closed views - static setupLibraryPanel(sidebarContainer: Doc, doc: Doc) { + static setupWorkspaces(doc: Doc) { // setup workspaces library item - doc.workspaces = Docs.Create.TreeDocument([], { - title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true, - }); + if (doc.worspaces === undefined) { + doc.workspaces = new PrefetchProxy(Docs.Create.TreeDocument([], { + title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true, + })); + } const newWorkspace = ScriptField.MakeScript(`createNewWorkspace()`); (doc.workspaces as Doc).contextMenuScripts = new List([newWorkspace!]); (doc.workspaces as Doc).contextMenuLabels = new List(["Create New Workspace"]); - doc.documents = Docs.Create.TreeDocument([], { - title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, - }); - + return doc.workspaces as Doc; + } + static setupDocumentCollection(doc: Doc) { + if (doc.documents === undefined) { + doc.documents = new PrefetchProxy(Docs.Create.TreeDocument([], { + title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, + })); + } + return doc.documents as Doc; + } + static setupRecentlyClosed(doc: Doc) { // setup Recently Closed library item - doc.recentlyClosed = Docs.Create.TreeDocument([], { - title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, - }); + if (doc.recentlyClosed === undefined) { + doc.recentlyClosed = new PrefetchProxy(Docs.Create.TreeDocument([], { + title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, + })); + } + // this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready + PromiseValue(Cast(doc.recentlyClosed, Doc)).then(recent => recent && PromiseValue(recent.data).then(DocListCast)); const clearAll = ScriptField.MakeScript(`self.data = new List([])`); (doc.recentlyClosed as Doc).contextMenuScripts = new List([clearAll!]); (doc.recentlyClosed as Doc).contextMenuLabels = new List(["Clear All"]); - return Docs.Create.ButtonDocument({ - _width: 50, _height: 25, title: "Library", fontSize: 10, - letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", - sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, doc.recentlyClosed as Doc, doc], { - title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "place", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true - }), - targetContainer: sidebarContainer, - onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;") - }); + return doc.recentlyClosed as Doc; + } + // setup the Library button which will display the library panel. This panel includes a collection of workspaces, documents, and recently closed views + static setupLibraryPanel(doc: Doc, sidebarContainer: Doc) { + const workspaces = CurrentUserUtils.setupWorkspaces(doc); + const documents = CurrentUserUtils.setupDocumentCollection(doc); + const recentlyClosed = CurrentUserUtils.setupRecentlyClosed(doc); + + if (doc["tabs-button-library"] === undefined) { + doc["tabs-button-library"] = new PrefetchProxy(Docs.Create.ButtonDocument({ + _width: 50, _height: 25, title: "Library", fontSize: 10, + letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", + sourcePanel: new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], { + title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "place", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true + })) as any as Doc, + targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, + onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;") + })); + } + return doc["tabs-button-library"] as Doc; } // setup the Search button which will display the search panel. - static setupSearchPanel(sidebarContainer: Doc) { - return Docs.Create.ButtonDocument({ - _width: 50, _height: 25, title: "Search", fontSize: 10, - letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", - sourcePanel: Docs.Create.QueryDocument({ title: "search stack", }), - targetContainer: sidebarContainer, - lockedPosition: true, - onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel") - }); + static setupSearchBtnPanel(doc: Doc, sidebarContainer: Doc) { + if (doc["tabs-button-search"] === undefined) { + doc["tabs-button-search"] = new PrefetchProxy(Docs.Create.ButtonDocument({ + _width: 50, _height: 25, title: "Search", fontSize: 10, + letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", + sourcePanel: new PrefetchProxy(Docs.Create.QueryDocument({ title: "search stack", })) as any as Doc, + targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, + lockedPosition: true, + onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel") + })); + } + return doc["tabs-button-search"] as Doc; } - // setup the list of sidebar mode buttons which determine what is displayed in the sidebar - static setupSidebarButtons(doc: Doc) { - const sidebarContainer = new Doc(); - doc.sidebarContainer = new PrefetchProxy(sidebarContainer); - sidebarContainer._chromeStatus = "disabled"; - sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()"); + static setupSidebarContainer(doc: Doc) { + if (doc["tabs-panelContainer"] === undefined) { + const sidebarContainer = new Doc(); + sidebarContainer._chromeStatus = "disabled"; + sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()"); + doc["tabs-panelContainer"] = new PrefetchProxy(sidebarContainer); + } + return doc["tabs-panelContainer"] as Doc; + } - doc.ToolsBtn = new PrefetchProxy(this.setupToolsPanel(sidebarContainer, doc)); - doc.LibraryBtn = new PrefetchProxy(this.setupLibraryPanel(sidebarContainer, doc)); - doc.SearchBtn = new PrefetchProxy(this.setupSearchPanel(sidebarContainer)); + // setup the list of sidebar mode buttons which determine what is displayed in the sidebar + static async setupSidebarButtons(doc: Doc) { + const sidebarContainer = CurrentUserUtils.setupSidebarContainer(doc); + const toolsBtn = await CurrentUserUtils.setupToolsBtnPanel(doc, sidebarContainer); + const libraryBtn = CurrentUserUtils.setupLibraryPanel(doc, sidebarContainer); + const searchBtn = CurrentUserUtils.setupSearchBtnPanel(doc, sidebarContainer); // Finally, setup the list of buttons to display in the sidebar - doc.sidebarButtons = new PrefetchProxy(Docs.Create.StackingDocument([doc.SearchBtn as any as Doc, doc.LibraryBtn as any as Doc, doc.ToolsBtn as any as Doc], { - _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", hideHeadings: true, ignoreClick: true, _chromeStatus: "view-mode", - title: "sidebar btn row stack", backgroundColor: "dimGray", - })); + if (doc["tabs-buttons"] === undefined) { + doc["tabs-buttons"] = new PrefetchProxy(Docs.Create.StackingDocument([searchBtn, libraryBtn, toolsBtn], { + _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", hideHeadings: true, ignoreClick: true, _chromeStatus: "view-mode", + title: "sidebar btn row stack", backgroundColor: "dimGray", + })); + (toolsBtn.onClick as ScriptField).script.run({ this: toolsBtn }); + } } static blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, { @@ -328,85 +448,101 @@ export class CurrentUserUtils { _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", forceActive: true, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true - })) as any as Doc; + })) as any as Doc static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ ...opts, dropAction: "alias", removeDropProperties: new List(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 - })) as any as Doc; + })) as any as Doc /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window static setupExpandingButtons(doc: Doc) { - doc.penBtn = CurrentUserUtils.ficon({ - onClick: ScriptField.MakeScript("activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)"), - author: "systemTemplates", title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.pen, this)`), activePen: doc - }) - doc.undoBtn = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" }); - doc.redoBtn = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" }); - doc.expandingButtons = CurrentUserUtils.blist({ title: "expanding buttons", ignoreClick: true }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.penBtn as Doc]); + if (doc.penBtn === undefined) { + doc.penBtn = CurrentUserUtils.ficon({ + onClick: ScriptField.MakeScript("activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)"), + author: "systemTemplates", title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.pen, this)`), activePen: doc + }); + } + if (doc.undoBtn === undefined) { + doc.undoBtn = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" }); + } + if (doc.redoBtn === undefined) { + doc.redoBtn = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" }); + } + if (doc.expandingButtons === undefined) { + doc.expandingButtons = CurrentUserUtils.blist({ title: "expanding buttons", ignoreClick: true }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.penBtn as Doc]); + } } // sets up the default set of documents to be shown in the Overlay layer static setupOverlays(doc: Doc) { - doc.overlays = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "Overlays", backgroundColor: "#aca3a6" })); + if (doc.overlays === undefined) { + doc.overlays = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "Overlays", backgroundColor: "#aca3a6" })); + } } // the initial presentation Doc to use static setupDefaultPresentation(doc: Doc) { - doc.presentationTemplate = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ title: "pres element template", backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data" })); - doc.curPresentation = Docs.Create.PresDocument(new List(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" }); + if (doc.presentationTemplate === undefined) { + doc.presentationTemplate = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ + title: "pres element template", backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data" + })); + } + if (doc.curPresentation === undefined) { + doc.curPresentation = Docs.Create.PresDocument(new List(), { + title: "Presentation", _viewType: CollectionViewType.Stacking, + _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" + }); + } } static setupMobileUploads(doc: Doc) { - doc.optionalRightCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "New mobile uploads" })); + if (doc.optionalRightCollection === undefined) { + doc.optionalRightCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "New mobile uploads" })); + } } - static setupChildClicks(doc: Doc) { - const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript( - "docCast(thisContainer.target).then((target) => { target && docCast(this.source).then((source) => { target.proto.data = new List([source || this]); } ); } )", - { target: Doc.name }), { title: "On Child Clicked (open in target)", _width: 300, _height: 200 }); - const onClick = Docs.Create.ScriptingDocument(undefined, { title: "onClick", "onClick-rawScript": "console.log('click')", isTemplateDoc: true, isTemplateForField: "onClick", _width: 300, _height: 200 }, "onClick"); - const onCheckedClick = Docs.Create.ScriptingDocument(undefined, - { title: "onCheckedClick", "onCheckedClick-rawScript": "console.log(heading + checked + containingTreeView)", "onCheckedClick-params": new List(["heading", "checked", "containingTreeView"]), isTemplateDoc: true, isTemplateForField: "onCheckedClick", _width: 300, _height: 200 }, "onCheckedClick"); - doc.childClickFuncs = Docs.Create.TreeDocument([openInTarget], { title: "on Child Click function templates" }); - doc.clickFuncs = Docs.Create.TreeDocument([onClick, onCheckedClick], { title: "onClick funcs" }); - } - - static updateUserDocument(doc: Doc) { - doc.title = Doc.CurrentUserEmail; - new InkingControl(); - (doc.childClickFuncs === undefined) && CurrentUserUtils.setupChildClicks(doc); - (doc.iconTypes === undefined) && CurrentUserUtils.setupDefaultIconTypes(doc); - (doc.templateDocs === undefined) && CurrentUserUtils.setupDefaultDocTemplates(doc); - (doc.optionalRightCollection === undefined) && CurrentUserUtils.setupMobileUploads(doc); - (doc.overlays === undefined) && CurrentUserUtils.setupOverlays(doc); - (doc.expandingButtons === undefined) && CurrentUserUtils.setupExpandingButtons(doc); - (doc.curPresentation === undefined) && CurrentUserUtils.setupDefaultPresentation(doc); - (doc.sidebarButtons === undefined) && CurrentUserUtils.setupSidebarButtons(doc); - doc.linkDb = Docs.Prototypes.MainLinkDocument(); + static setupClickEditorTemplates(doc: Doc) { + if (doc.childClickFuncs === undefined) { + const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript( + "docCast(thisContainer.target).then((target) => { target && docCast(this.source).then((source) => { target.proto.data = new List([source || this]); } ); } )", + { target: Doc.name }), { title: "On Child Clicked (open in target)", _width: 300, _height: 200 }); + doc.childClickFuncs = Docs.Create.TreeDocument([openInTarget], { title: "on Child Click function templates" }); + } // this is equivalent to using PrefetchProxies to make sure all the childClickFuncs have been retrieved. PromiseValue(Cast(doc.childClickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); - // this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready - PromiseValue(Cast(doc.recentlyClosed, Doc)).then(recent => recent && PromiseValue(recent.data).then(DocListCast)); - // this is equivalent to using PrefetchProxies to make sure all the sidebarButtons and noteType internal Doc's have been retrieved. - PromiseValue(Cast(doc.noteTypes, Doc)).then(noteTypes => noteTypes && PromiseValue(noteTypes.data).then(DocListCast)); + + if (doc.clickFuncs === undefined) { + const onClick = Docs.Create.ScriptingDocument(undefined, { + title: "onClick", "onClick-rawScript": "console.log('click')", + isTemplateDoc: true, isTemplateForField: "onClick", _width: 300, _height: 200 + }, "onClick"); + const onCheckedClick = Docs.Create.ScriptingDocument(undefined, { + title: "onCheckedClick", "onCheckedClick-rawScript": "console.log(heading + checked + containingTreeView)", "onCheckedClick-params": new List(["heading", "checked", "containingTreeView"]), isTemplateDoc: true, isTemplateForField: "onCheckedClick", _width: 300, _height: 200 + }, "onCheckedClick"); + doc.clickFuncs = Docs.Create.TreeDocument([onClick, onCheckedClick], { title: "onClick funcs" }); + } PromiseValue(Cast(doc.clickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); - PromiseValue(Cast(doc.childClickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); - PromiseValue(Cast(doc.sidebarButtons, Doc)).then(stackingDoc => { - stackingDoc && PromiseValue(Cast(stackingDoc.data, listSpec(Doc))).then(sidebarButtons => { - sidebarButtons?.map((sidebarBtn, i) => { - sidebarBtn && PromiseValue(Cast(sidebarBtn, Doc)).then(async btn => { // choose which item to display first in sidebar panel (i === 0,1, or 2) - btn?.sourcePanel && btn.targetContainer && i === 2 && (btn.onClick as ScriptField).script.run({ this: btn }); - }); - }); - }); - }); + + return doc.clickFuncs as Doc; + } + + static async updateUserDocument(doc: Doc) { + new InkingControl(); + doc.title = Doc.CurrentUserEmail; + doc.activePen = doc; + CurrentUserUtils.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon + CurrentUserUtils.setupMobileUploads(doc); // sets up the optional right collection of documents uploaded from mobile + CurrentUserUtils.setupOverlays(doc); // documents in overlay layer + CurrentUserUtils.setupExpandingButtons(doc); // the bottom bar of font icons + CurrentUserUtils.setupDefaultPresentation(doc); // presentation that's initially triggered + await CurrentUserUtils.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels + doc.linkDb = Docs.Prototypes.MainLinkDocument(); // setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet doc.undoBtn && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc.undoBtn as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); doc.redoBtn && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc.redoBtn as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); - this.updateCreatorButtons(doc); return doc; } diff --git a/src/server/database.ts b/src/server/database.ts index 1da31c5ff..d74bd7321 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -52,9 +52,6 @@ export namespace Database { private currentWrites: { [id: string]: Promise } = {}; private db?: mongodb.Db; private onConnect: (() => void)[] = []; - constructor() { - } - doConnect() { console.error(`\nConnecting to Mongo with URL : ${url}\n`); this.MongoClient.connect(url, { connectTimeoutMS: 30000, socketTimeoutMS: 30000, useUnifiedTopology: true }, (_err, client) => { -- cgit v1.2.3-70-g09d2