From 67c56296339bd1c760b704c1d14710ec6f575d49 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 17 Apr 2020 22:55:10 -0400 Subject: added freeze button for web boxes. cleaned up pointerevent setting throughout code. --- src/client/views/collections/CollectionTreeView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d2c8cc3ad..510c9924b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -453,7 +453,7 @@ class TreeView extends React.Component { fontWeight: this.props.document.searchMatch ? "bold" : undefined, textDecoration: Doc.GetT(this.props.document, "title", "string", true) ? "underline" : undefined, outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined, - pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none" + pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? undefined : "none" }} > {Doc.GetT(this.props.document, "editTitle", "boolean", true) ? this.editableView("title") : -- cgit v1.2.3-70-g09d2 From d3aebc8404685496673a8611a6d72ff7695ad191 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 18 Apr 2020 13:42:03 -0400 Subject: several pointerevent fixes broken by last change. added scroll to target for webBox links. --- src/client/util/DocumentManager.ts | 13 ++- .../views/collections/CollectionTreeView.tsx | 1 - .../collectionFreeForm/CollectionFreeFormView.tsx | 6 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 1 - src/client/views/nodes/DocumentView.scss | 10 -- src/client/views/nodes/DocumentView.tsx | 118 ++++++++++----------- src/client/views/nodes/FormattedTextBoxComment.tsx | 4 +- src/client/views/nodes/LinkAnchorBox.scss | 1 + src/client/views/nodes/LinkAnchorBox.tsx | 2 + src/client/views/nodes/LinkBox.tsx | 1 - src/client/views/nodes/WebBox.tsx | 22 ++-- src/client/views/pdf/Annotation.tsx | 4 +- src/client/views/pdf/PDFViewer.tsx | 8 +- 13 files changed, 100 insertions(+), 91 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 2d6078cf3..e66e67723 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -156,7 +156,12 @@ export class DocumentManager { let annotatedDoc = await Cast(targetDoc.annotationOn, Doc); if (annotatedDoc) { const first = getFirstDocView(annotatedDoc); - if (first) annotatedDoc = first.props.Document; + if (first) { + annotatedDoc = first.props.Document; + if (docView) { + docView.props.focus(annotatedDoc, false); + } + } } if (docView) { // we have a docView already and aren't forced to create a new one ... just focus on the document. TODO move into view if necessary otherwise just highlight? docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish); @@ -219,9 +224,9 @@ export class DocumentManager { if (linkDoc) { const target = (doc === linkDoc.anchor1 ? linkDoc.anchor2 : doc === linkDoc.anchor2 ? linkDoc.anchor1 : (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? linkDoc.anchor2 : linkDoc.anchor1)) as Doc; - const targetTimecode = (doc === linkDoc.anchor1 ? Cast(linkDoc.anchor2_timecode, "number") : - doc === linkDoc.anchor2 ? Cast(linkDoc.anchor1_timecode, "number"): - (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? Cast(linkDoc.anchor2_timecode, "number"):Cast(linkDoc.anchor1_timecode, "number"))); + const targetTimecode = (doc === linkDoc.anchor1 ? Cast(linkDoc.anchor2_timecode, "number") : + doc === linkDoc.anchor2 ? Cast(linkDoc.anchor1_timecode, "number") : + (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? Cast(linkDoc.anchor2_timecode, "number") : Cast(linkDoc.anchor1_timecode, "number"))); if (target) { const containerDoc = (await Cast(target.annotationOn, Doc)) || target; containerDoc.currentTimecode = targetTimecode; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 510c9924b..5ff8c11ee 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -145,7 +145,6 @@ class TreeView extends React.Component { ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this))); } - onPointerDown = (e: React.PointerEvent) => e.stopPropagation(); onPointerEnter = (e: React.PointerEvent): void => { this.props.active(true) && Doc.BrushDoc(this.dataDoc); if (e.buttons === 1 && SelectionManager.GetIsDragging()) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 02f9bd487..b3409bd57 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -804,7 +804,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u if (!annotOn) { this.props.focus(doc); } else { - const contextHgt = Doc.AreProtosEqual(annotOn, this.props.Document) && this.props.VisibleHeight ? this.props.VisibleHeight() : NumCast(annotOn.height); + const contextHgt = Doc.AreProtosEqual(annotOn, this.props.Document) && this.props.VisibleHeight ? this.props.VisibleHeight() : NumCast(annotOn._height); const offset = annotOn && (contextHgt / 2 * 96 / 72); this.props.Document.scrollY = NumCast(doc.y) - offset; } @@ -820,7 +820,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u const savedState = { px: this.Document._panX, py: this.Document._panY, s: this.Document.scale, pt: this.Document.panTransformType }; - if (!willZoom) { + if (!willZoom && DocumentView._focusHack.length) { Doc.BrushDoc(this.props.Document); !doc.z && this.scaleAtPt(DocumentView._focusHack, 1); // [NumCast(doc.x), NumCast(doc.y)], 1); } else { @@ -995,7 +995,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u {...this.getChildDocumentViewProps(pair.layout, pair.data)} dataProvider={this.childDataProvider} LayoutDoc={this.childLayoutDocFunc} - pointerEvents={this.props.layoutEngine?.() !== undefined ? "none" : undefined} + pointerEvents={this.props.layoutEngine?.() !== undefined ? false : undefined} jitterRotation={NumCast(this.props.Document.jitterRotation)} fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)} FreezeDimensions={BoolCast(this.props.freezeChildDimensions)} diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 05ad98c43..e325a70c0 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -22,7 +22,6 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { width?: number; height?: number; jitterRotation: number; - pointerEvents?: "none"; transition?: string; fitToBox?: boolean; } diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index fc9ee1201..81ae36cc0 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -38,16 +38,6 @@ display:flex; overflow: hidden; } - .documentView-linkAnchorBoxWrapper { - pointer-events: none; - position: absolute; - transform-origin: top left; - width: 100%; - height: 100%; - top:0; - left:0; - z-index: 1; - } .documentView-lock { width: 20; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 2f22488e4..2bae2fa96 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -80,6 +80,7 @@ export interface DocumentViewProps { ContentScaling: () => number; PanelWidth: () => number; PanelHeight: () => number; + pointerEvents?: boolean; focus: (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: DocFocusFunc) => void; parentActive: (outsideReaction: boolean) => boolean; whenActiveChanged: (isActive: boolean) => void; @@ -994,38 +995,42 @@ export class DocumentView extends DocComponent(Docu screenToLocalTransform = () => this.props.ScreenToLocalTransform(); @computed get contents() { TraceMobx(); - return (); + return (<> + + {this.anchors} + + ); } linkEndpoint = (linkDoc: Doc) => Doc.LinkEndpoint(linkDoc, this.props.Document); @@ -1049,20 +1054,19 @@ export class DocumentView extends DocComponent(Docu @computed get anchors() { TraceMobx(); return this.layoutDoc.presBox ? (null) : DocListCast(this.Document.links).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) => -
- -
); + ); } @computed get innards() { TraceMobx(); @@ -1101,22 +1105,18 @@ export class DocumentView extends DocComponent(Docu SetValue={undoBatch((value: string) => (Doc.GetProto(this.props.DataDoc || this.props.Document)[showTitle] = value) ? true : true)} /> ); - return <> - {this.anchors} - {!showTitle && !showCaption ? - this.contents : -
-
- {this.contents} -
- {titleView} - {captionView} + return !showTitle && !showCaption ? + this.contents : +
+
+ {this.contents}
- } - ; + {titleView} + {captionView} +
; } @computed get ignorePointerEvents() { - return (this.Document.isBackground && !this.isSelected() && !SelectionManager.GetIsDragging()) || this.props.layoutKey?.includes("layout_key") || (this.Document.type === DocumentType.INK && InkingControl.Instance.selectedTool !== InkTool.None); + return this.props.pointerEvents === false || (this.Document.isBackground && !this.isSelected() && !SelectionManager.GetIsDragging()) || (this.Document.type === DocumentType.INK && InkingControl.Instance.selectedTool !== InkTool.None); } @observable _animate = 0; diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx index 35304033f..41df5b3c1 100644 --- a/src/client/views/nodes/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/FormattedTextBoxComment.tsx @@ -16,6 +16,7 @@ import React = require("react"); import { Docs } from "../../documents/Documents"; import wiki from "wikijs"; import { DocumentType } from "../../documents/DocumentTypes"; +import { DocumentView } from "./DocumentView"; export let formattedTextBoxCommentPlugin = new Plugin({ view(editorView) { return new FormattedTextBoxComment(editorView); } @@ -85,8 +86,9 @@ export class FormattedTextBoxComment { const textBox = FormattedTextBoxComment.textBox; if (FormattedTextBoxComment.linkDoc && !keep && textBox) { if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) { - textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab":"onRight"); + textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight"); } else { + DocumentView._focusHack = []; DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); } diff --git a/src/client/views/nodes/LinkAnchorBox.scss b/src/client/views/nodes/LinkAnchorBox.scss index 24f9c1ea0..710f2178b 100644 --- a/src/client/views/nodes/LinkAnchorBox.scss +++ b/src/client/views/nodes/LinkAnchorBox.scss @@ -5,6 +5,7 @@ height: 15; border-radius: 20px; user-select: none; + pointer-events: all; .linkAnchorBox-linkCloser { position: absolute; diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 13ffc6956..3b1ced815 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -17,6 +17,7 @@ import { LinkEditor } from "../linking/LinkEditor"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { SelectionManager } from "../../util/SelectionManager"; import { TraceMobx } from "../../../new_fields/util"; +import { DocumentView } from "./DocumentView"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -74,6 +75,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent { + DocumentView._focusHack = []; DocumentManager.Instance.FollowLink(this.rootDoc, anchorContainerDoc, document => this.props.addDocTab(document, StrCast(this.layoutDoc.linkOpenLocation, "inTab")), false); this._editing = false; }), 300 - (Date.now() - this._lastTap)); diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index af4bf420f..740f2ef04 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -17,7 +17,6 @@ export class LinkBox extends ViewBoxBaseComponent( public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkBox, fieldKey); } render() { return
e.button === 0 && !e.ctrlKey && e.stopPropagation()} style={{ background: this.props.backgroundColor?.(this.props.Document) }} > (); private _iframeRef = React.createRef(); private _iframeIndicatorRef = React.createRef(); private _iframeDragRef = React.createRef(); - @observable private _pressX: number = 0; - @observable private _pressY: number = 0; - private _scrollTop = 0; + private _reactionDisposer?: IReactionDisposer; private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void); iframeLoaded = action((e: any) => { @@ -53,6 +52,16 @@ export class WebBox extends ViewBoxAnnotatableComponent this.layoutDoc.scrollY, + (scrollY) => { + if (scrollY !== undefined) { + this._outerRef.current!.scrollTop = scrollY; + this.layoutDoc.scrollY = undefined; + } + }, + { fireImmediately: true } + ); }); setPreviewCursor = (func?: (x: number, y: number, drag: boolean) => void) => this._setPreviewCursor = func; iframedown = (e: PointerEvent) => { @@ -60,7 +69,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { const scroll = (e.target as any)?.children?.[0].scrollTop; - this.layoutDoc.scrollTop = this._outerRef.current!.scrollTop = this._scrollTop = scroll; + this.layoutDoc.scrollTop = this._outerRef.current!.scrollTop = scroll; } async componentDidMount() { @@ -87,6 +96,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { else if (e.button === 0) { const annoGroup = await Cast(this.props.document.group, Doc); if (annoGroup) { - DocumentManager.Instance.FollowLink(undefined, annoGroup, (doc, followLinkLocation) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation), false, undefined); + DocumentView._focusHack = []; + DocumentManager.Instance.FollowLink(undefined, annoGroup, (doc, followLinkLocation) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation), false, undefined); e.stopPropagation(); } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 948d2300d..75be08e9f 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -9,7 +9,7 @@ import { List } from "../../../new_fields/List"; import { makeInterface, createSchema } from "../../../new_fields/Schema"; import { ScriptField, ComputedField } from "../../../new_fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { smoothScroll, Utils, emptyFunction, returnOne, intersectRect, addStyleSheet, addStyleSheetRule, clearStyleSheetRules, returnZero } from "../../../Utils"; +import { smoothScroll, Utils, emptyFunction, returnOne, intersectRect, addStyleSheet, addStyleSheetRule, clearStyleSheetRules, returnZero, emptyPath } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { CompiledScript, CompileScript } from "../../util/Scripting"; @@ -607,7 +607,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent { - if (!this.props.Document[HeightSym]() || !this.props.Document.nativeHeight) { + if (!this.props.Document[HeightSym]() || !this.props.Document._nativeHeight) { setTimeout((() => { this.Document._height = this.Document[WidthSym]() * this._coverPath.height / this._coverPath.width; this.Document._nativeHeight = (this.Document._nativeWidth || 0) * this._coverPath.height / this._coverPath.width; @@ -632,7 +632,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent + return
{this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map((anno, index) => )}
; @@ -643,7 +643,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent 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/client/views/collections/CollectionTreeView.tsx') 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 34ee553af7b2133632b66f966c07fd1bb1085e81 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 19 Apr 2020 00:30:23 -0400 Subject: changed tree view to show context menu icon to avoid right-clicking --- src/Utils.ts | 29 +++++++++++++++ src/client/views/DocumentDecorations.tsx | 33 ++--------------- .../views/collections/CollectionTreeView.scss | 31 +++++++++------- .../views/collections/CollectionTreeView.tsx | 42 ++++++++++++---------- src/client/views/nodes/DocumentView.tsx | 6 ++-- 5 files changed, 76 insertions(+), 65 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index 58f272ba5..9acdc8731 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -470,6 +470,35 @@ export function clearStyleSheetRules(sheet: any) { return false; } +export function simulateMouseClick(element: Element, x: number, y: number, sx: number, sy: number) { + ["pointerdown", "pointerup"].map(event => element.dispatchEvent( + new PointerEvent(event, { + view: window, + bubbles: true, + cancelable: true, + button: 2, + pointerType: "mouse", + clientX: x, + clientY: y, + screenX: sx, + screenY: sy, + }))); + + element.dispatchEvent( + new MouseEvent("contextmenu", { + view: window, + bubbles: true, + cancelable: true, + button: 2, + clientX: x, + clientY: y, + movementX: 0, + movementY: 0, + screenX: sx, + screenY: sy, + })); +} + export function setupMoveUpEvents( target: object, e: React.PointerEvent, diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index c49fe157c..9ba418d74 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -8,7 +8,7 @@ import { PositionDocument } from '../../new_fields/documentSchemas'; import { ScriptField } from '../../new_fields/ScriptField'; import { Cast, StrCast, NumCast } from "../../new_fields/Types"; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; -import { Utils, setupMoveUpEvents, emptyFunction, returnFalse } from "../../Utils"; +import { Utils, setupMoveUpEvents, emptyFunction, returnFalse, simulateMouseClick } from "../../Utils"; import { DocUtils } from "../documents/Documents"; import { DocumentType } from '../documents/DocumentTypes'; import { DragManager } from "../util/DragManager"; @@ -142,40 +142,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @action onSettingsDown = (e: React.PointerEvent): void => { setupMoveUpEvents(this, e, () => false, (e) => { }, this.onSettingsClick); } - - simulateMouseClick(element: Element, x: number, y: number, sx: number, sy: number) { - ["pointerdown", "pointerup"].map(event => element.dispatchEvent( - new PointerEvent(event, { - view: window, - bubbles: true, - cancelable: true, - button: 2, - pointerType: "mouse", - clientX: x, - clientY: y, - screenX: sx, - screenY: sy, - }))); - - element.dispatchEvent( - new MouseEvent("contextmenu", { - view: window, - bubbles: true, - cancelable: true, - button: 2, - clientX: x, - clientY: y, - movementX: 0, - movementY: 0, - screenX: sx, - screenY: sy, - })); - } @action onSettingsClick = (e: PointerEvent): void => { if (e.button === 0 && !e.altKey && !e.ctrlKey) { let child = SelectionManager.SelectedDocuments()[0].ContentDiv!.children[0]; while (child.children.length && child.className !== "jsx-parser") child = child.children[0]; - this.simulateMouseClick(child.children[0], e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); + simulateMouseClick(child.children[0], e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); } } diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 8e95f7fbe..1e59c493f 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -100,10 +100,29 @@ border-left: dashed 1px #00000042; } +.treeViewItem-header { + border: transparent 1px solid; + display: flex; + + .editableView-container-editing-oneLine { + min-width: 15px; + } + .documentView-node-topmost { + width: unset; + } + > svg { + display: none; + } + +} + .treeViewItem-header:hover { .collectionTreeView-keyHeader { display: inherit; } + > svg { + display: inherit; + } .treeViewItem-openRight { display: inline-block; @@ -119,18 +138,6 @@ } } -.treeViewItem-header { - border: transparent 1px solid; - display: flex; - - .editableView-container-editing-oneLine { - min-width: 15px; - } - .documentView-node-topmost { - width: unset; - } -} - .treeViewItem-header-above { border-top: black 1px solid; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 2df1614de..c2838a15e 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -10,7 +10,7 @@ import { Document, listSpec, createSchema, makeInterface } from '../../../new_fi import { ComputedField, ScriptField } from '../../../new_fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../new_fields/Types'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; -import { emptyFunction, emptyPath, returnFalse, Utils, returnOne, returnZero, returnTransparent, returnTrue } from '../../../Utils'; +import { emptyFunction, emptyPath, returnFalse, Utils, returnOne, returnZero, returnTransparent, returnTrue, simulateMouseClick } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from "../../documents/DocumentTypes"; import { DocumentManager } from '../../util/DocumentManager'; @@ -182,16 +182,12 @@ class TreeView extends React.Component { SetValue={undoBatch((value: string) => { Doc.SetInPlace(this.props.document, key, value, false) || true; Doc.SetInPlace(this.props.document, "editTitle", undefined, false); - //this.props.document.editTitle = undefined; })} OnFillDown={undoBatch((value: string) => { Doc.SetInPlace(this.props.document, key, value, false); const doc = Docs.Create.FreeformDocument([], { title: "-", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); - //EditableView.loadId = doc[Id]; Doc.SetInPlace(this.props.document, "editTitle", undefined, false); - // this.props.document.editTitle = undefined; Doc.SetInPlace(this.props.document, "editTitle", true, false); - //doc.editTitle = true; return this.props.addDocument(doc); })} onClick={() => { @@ -399,11 +395,16 @@ class TreeView extends React.Component {
    ; } + showContextMenu = (e: React.MouseEvent) => { + simulateMouseClick(this._docRef.current!.ContentDiv!, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); + e.stopPropagation(); + } focusOnDoc = (doc: Doc) => DocumentManager.Instance.getFirstDocumentView(doc)?.props.focus(doc, true); contextMenuItems = () => { const focusScript = ScriptField.MakeFunction(`DocFocus(self)`); return [{ script: focusScript!, label: "Focus" }]; } + _docRef = React.createRef(); /** * Renders the EditableView title element for placement into the tree. */ @@ -413,18 +414,21 @@ class TreeView extends React.Component { const editTitle = ScriptField.MakeFunction("setInPlace(this, 'editTitle', true)"); const headerElements = ( - { - if (this.treeViewOpen) { - this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" : - this.treeViewExpandedView === "fields" && Doc.Layout(this.props.document) ? "layout" : - this.treeViewExpandedView === "layout" && this.props.document.links ? "links" : - this.childDocs ? this.fieldKey : "fields"; - } - this.treeViewOpen = true; - })}> - {this.treeViewExpandedView} - ); + <> + this.showContextMenu(e)}> + { + if (this.treeViewOpen) { + this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" : + this.treeViewExpandedView === "fields" && Doc.Layout(this.props.document) ? "layout" : + this.treeViewExpandedView === "layout" && this.props.document.links ? "links" : + this.childDocs ? this.fieldKey : "fields"; + } + this.treeViewOpen = true; + })}> + {this.treeViewExpandedView} + + ); const openRight = (
    ); @@ -440,6 +444,7 @@ class TreeView extends React.Component { {Doc.GetT(this.props.document, "editTitle", "boolean", true) ? this.editableView("title") : { } render() { + const sorting = this.props.document[`${this.fieldKey}-sortAscending`]; setTimeout(() => runInAction(() => untracked(() => this._overrideTreeViewOpen = this.treeViewOpen)), 0); return
  • @@ -481,7 +487,7 @@ class TreeView extends React.Component { {this.renderBullet} {this.renderTitle}
  • -
    +
    {!this.treeViewOpen || this.props.renderedIds.indexOf(this.props.document[Id]) !== -1 ? (null) : this.renderContent}
    diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 12f5b27e1..d114698ea 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -823,11 +823,9 @@ export class DocumentView extends DocComponent(Docu icon: "brain" }); - cm.addItem({ description: "Recommender System", subitems: recommender_subitems, icon: "brain" }); - - - moreItems.push({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" }); moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" }); + moreItems.push({ description: "Recommender System", subitems: recommender_subitems, icon: "brain" }); + moreItems.push({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" }); moreItems.push({ description: "Undo Debug Test", event: () => UndoManager.TraceOpenBatches(), icon: "exclamation" }); !more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" }); runInAction(() => { -- 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/client/views/collections/CollectionTreeView.tsx') 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/client/views/collections/CollectionTreeView.tsx') 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 From 26949f548619c93fc13bc0f3cfcec6cf9e72f3d6 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 19 Apr 2020 18:50:21 -0400 Subject: final structural cleanp up of UserDocument for a while, hopefully --- src/client/documents/Documents.ts | 7 +- src/client/util/SelectionManager.ts | 6 +- src/client/util/SharingManager.tsx | 2 +- src/client/views/DocumentButtonBar.tsx | 5 +- src/client/views/DocumentDecorations.tsx | 9 +- src/client/views/GlobalKeyHandler.ts | 7 +- src/client/views/InkingControl.tsx | 18 +-- src/client/views/MainView.tsx | 20 +-- src/client/views/OverlayView.tsx | 23 ++- .../views/collections/CollectionDockingView.tsx | 16 +- .../views/collections/CollectionTimeView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 15 +- src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/PresBox.tsx | 8 +- src/mobile/ImageUpload.tsx | 2 +- src/mobile/MobileInterface.tsx | 53 +++---- src/new_fields/Doc.ts | 18 ++- .../authentication/models/current_user_utils.ts | 171 ++++++++++----------- 18 files changed, 184 insertions(+), 202 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 209a72d52..d231f42e8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -8,7 +8,6 @@ import { PDFBox } from "../views/nodes/PDFBox"; import { ScriptingBox } from "../views/nodes/ScriptingBox"; import { VideoBox } from "../views/nodes/VideoBox"; import { WebBox } from "../views/nodes/WebBox"; -import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; import { OmitKeys, JSONUtils, Utils } from "../../Utils"; import { Field, Doc, Opt, DocListCastAsync, FieldResult, DocListCast } from "../../new_fields/Doc"; import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField } from "../../new_fields/URLField"; @@ -239,7 +238,7 @@ export namespace Docs { [DocumentType.LINKDB, { data: new List(), layout: { view: EmptyBox, dataField: data }, - options: { childDropAction: "alias", title: "LINK DB" } + options: { childDropAction: "alias", title: "Global Link Database" } }], [DocumentType.SCRIPTING, { layout: { view: ScriptingBox, dataField: data } @@ -960,7 +959,7 @@ export namespace DocUtils { export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = "", id?: string) { const sv = DocumentManager.Instance.getDocumentView(source.doc); if (sv && sv.props.ContainingCollectionDoc === target.doc) return; - if (target.doc === CurrentUserUtils.UserDocument) return undefined; + if (target.doc === Doc.UserDoc()) return undefined; const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship }, id); Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('self.anchor1.title +" (" + (self.linkRelationship||"to") +") " + self.anchor2.title'); @@ -990,7 +989,7 @@ export namespace DocUtils { }); ContextMenu.Instance.addItem({ description: "Add Template Doc ...", - subitems: DocListCast(Cast(Doc.UserDoc().expandingButtons, Doc, null)?.data).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc).map((dragDoc, i) => ({ + subitems: DocListCast(Cast(Doc.UserDoc().dockedBtns, Doc, null)?.data).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc).map((dragDoc, i) => ({ description: ":" + StrCast(dragDoc.title), event: (args: { x: number, y: number }) => { const newDoc = Doc.ApplyTemplate(dragDoc); diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 6c386d684..a49977c42 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -28,21 +28,21 @@ export namespace SelectionManager { manager.SelectedDocuments.clear(); manager.SelectedDocuments.set(docView, true); } - Doc.UserDoc().SelectedDocs = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document)); + Doc.UserDoc().activeSelection = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document)); } @action DeselectDoc(docView: DocumentView): void { if (manager.SelectedDocuments.get(docView)) { manager.SelectedDocuments.delete(docView); docView.props.whenActiveChanged(false); - Doc.UserDoc().SelectedDocs = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document)); + Doc.UserDoc().activeSelection = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document)); } } @action DeselectAll(): void { Array.from(manager.SelectedDocuments.keys()).map(dv => dv.props.whenActiveChanged(false)); manager.SelectedDocuments.clear(); - Doc.UserDoc().SelectedDocs = new List([]); + Doc.UserDoc().activeSelection = new List([]); } } diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 7496ac73c..3ce6de80d 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -109,7 +109,7 @@ export default class SharingManager extends React.Component<{}> { if (isCandidate) { const userDocument = await DocServer.GetRefField(user.userDocumentId); if (userDocument instanceof Doc) { - const notificationDoc = await Cast(userDocument.optionalRightCollection, Doc); + const notificationDoc = await Cast(userDocument.rightSidebarCollection, Doc); runInAction(() => { if (notificationDoc instanceof Doc) { this.users.push({ user, notificationDoc }); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 5b78008ab..93987b751 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -21,7 +21,6 @@ import { Template, Templates } from "./Templates"; import React = require("react"); import { DragManager } from '../util/DragManager'; import { MetadataEntryMenu } from './MetadataEntryMenu'; -import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; @@ -202,9 +201,9 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | @computed get pinButton() { const targetDoc = this.view0?.props.Document; - const isPinned = targetDoc && CurrentUserUtils.IsDocPinned(targetDoc); + const isPinned = targetDoc && Doc.isDocPinned(targetDoc); return !targetDoc ? (null) :
    { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 9ba418d74..c8766a6b3 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -7,7 +7,6 @@ import { Doc, DataSym } from "../../new_fields/Doc"; import { PositionDocument } from '../../new_fields/documentSchemas'; import { ScriptField } from '../../new_fields/ScriptField'; import { Cast, StrCast, NumCast } from "../../new_fields/Types"; -import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { Utils, setupMoveUpEvents, emptyFunction, returnFalse, simulateMouseClick } from "../../Utils"; import { DocUtils } from "../documents/Documents"; import { DocumentType } from '../documents/DocumentTypes'; @@ -69,7 +68,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> get Bounds(): { x: number, y: number, b: number, r: number } { return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => { if (documentView.props.renderDepth === 0 || - Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) { + Doc.AreProtosEqual(documentView.props.Document, Doc.UserDoc())) { return bounds; } const transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse(); @@ -164,7 +163,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> dragData.isSelectionMove = true; this.Interacting = true; this._hidden = true; - DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(documentView => documentView.ContentDiv!), dragData, e.x, e.y, { + DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(dv => dv.ContentDiv!), dragData, e.x, e.y, { dragComplete: action(e => this._hidden = this.Interacting = false), hideSource: true }); @@ -178,14 +177,14 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @action onCloseClick = async (e: PointerEvent) => { if (e.button === 0) { - const recent = Cast(CurrentUserUtils.UserDocument.recentlyClosed, Doc) as Doc; + const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc; const selected = SelectionManager.SelectedDocuments().slice(); SelectionManager.DeselectAll(); this._addedCloseCalls.forEach(handler => handler(selected)); selected.map(dv => { recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true); - dv.props.removeDocument && dv.props.removeDocument(dv.props.Document); + dv.props.removeDocument?.(dv.props.Document); }); } } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index d01f3f1e5..185222541 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -7,7 +7,6 @@ import { action, runInAction } from "mobx"; import { Doc } from "../../new_fields/Doc"; import { DictationManager } from "../util/DictationManager"; import SharingManager from "../util/SharingManager"; -import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; import { Cast, PromiseValue, NumCast } from "../../new_fields/Types"; import { ScriptField } from "../../new_fields/ScriptField"; import { InkingControl } from "./InkingControl"; @@ -194,7 +193,7 @@ export default class KeyManager { } break; case "t": - PromiseValue(Cast(CurrentUserUtils.UserDocument.Create, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + PromiseValue(Cast(Doc.UserDoc()["tabs-button-tools"], Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); if (MainView.Instance.flyoutWidth === 240) { MainView.Instance.flyoutWidth = 0; } else { @@ -202,7 +201,7 @@ export default class KeyManager { } break; case "l": - PromiseValue(Cast(CurrentUserUtils.UserDocument.Library, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + PromiseValue(Cast(Doc.UserDoc()["tabs-button-library"], Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); if (MainView.Instance.flyoutWidth === 250) { MainView.Instance.flyoutWidth = 0; } else { @@ -210,7 +209,7 @@ export default class KeyManager { } break; case "f": - PromiseValue(Cast(CurrentUserUtils.UserDocument.Search, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + PromiseValue(Cast(Doc.UserDoc()["tabs-button-search"], Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); if (MainView.Instance.flyoutWidth === 400) { MainView.Instance.flyoutWidth = 0; } else { diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 645c7fa54..172c1864a 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -12,9 +12,9 @@ import { FormattedTextBox } from "./nodes/FormattedTextBox"; export class InkingControl { @observable static Instance: InkingControl; - @computed private get _selectedTool(): InkTool { return FieldValue(NumCast(CurrentUserUtils.UserDocument.inkTool)) ?? InkTool.None; } - @computed private get _selectedColor(): string { return GestureOverlay.Instance.Color ?? FieldValue(StrCast(CurrentUserUtils.UserDocument.inkColor)) ?? "rgb(244, 67, 54)"; } - @computed private get _selectedWidth(): string { return GestureOverlay.Instance.Width?.toString() ?? FieldValue(StrCast(CurrentUserUtils.UserDocument.inkWidth)) ?? "5"; } + @computed private get _selectedTool(): InkTool { return FieldValue(NumCast(Doc.UserDoc().inkTool)) ?? InkTool.None; } + @computed private get _selectedColor(): string { return GestureOverlay.Instance.Color ?? FieldValue(StrCast(Doc.UserDoc().inkColor)) ?? "rgb(244, 67, 54)"; } + @computed private get _selectedWidth(): string { return GestureOverlay.Instance.Width?.toString() ?? FieldValue(StrCast(Doc.UserDoc().inkWidth)) ?? "5"; } @observable public _open: boolean = false; constructor() { @@ -23,7 +23,7 @@ export class InkingControl { switchTool = action((tool: InkTool): void => { // this._selectedTool = tool; - CurrentUserUtils.UserDocument.inkTool = tool; + Doc.UserDoc().inkTool = tool; }); decimalToHexString(number: number) { if (number < 0) { @@ -34,7 +34,7 @@ export class InkingControl { @undoBatch switchColor = action((color: ColorState): void => { - CurrentUserUtils.UserDocument.inkColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff"); + Doc.UserDoc().inkColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff"); if (InkingControl.Instance.selectedTool === InkTool.None) { const selected = SelectionManager.SelectedDocuments(); @@ -44,9 +44,9 @@ export class InkingControl { view.props.Document.isTemplateForField ? view.props.Document : Doc.GetProto(view.props.Document); if (targetDoc) { if (StrCast(Doc.Layout(view.props.Document).layout).indexOf("FormattedTextBox") !== -1 && FormattedTextBox.HadSelection) { - Doc.Layout(view.props.Document).color = CurrentUserUtils.UserDocument.inkColor; + Doc.Layout(view.props.Document).color = Doc.UserDoc().inkColor; } else { - Doc.Layout(view.props.Document)._backgroundColor = CurrentUserUtils.UserDocument.inkColor; // '_backgroundColor' is template specific. 'backgroundColor' would apply to all templates, but has no UI at the moment + Doc.Layout(view.props.Document)._backgroundColor = Doc.UserDoc().inkColor; // '_backgroundColor' is template specific. 'backgroundColor' would apply to all templates, but has no UI at the moment } } }); @@ -57,7 +57,7 @@ export class InkingControl { @action switchWidth = (width: string): void => { // this._selectedWidth = width; - CurrentUserUtils.UserDocument.inkWidth = width; + Doc.UserDoc().inkWidth = width; } @computed @@ -73,7 +73,7 @@ export class InkingControl { @action updateSelectedColor(value: string) { // this._selectedColor = value; - CurrentUserUtils.UserDocument.inkColor = value; + Doc.UserDoc().inkColor = value; } @computed diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 0877cc5f6..f8e246315 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -204,7 +204,7 @@ export class MainView extends React.Component { @action createNewWorkspace = async (id?: string) => { - const workspaces = Cast(this.userDoc.workspaces, Doc) as Doc; + const workspaces = Cast(this.userDoc.myWorkspaces, Doc) as Doc; const workspaceCount = DocListCast(workspaces.data).length + 1; const freeformOptions: DocumentOptions = { x: 0, @@ -214,8 +214,8 @@ export class MainView extends React.Component { title: "Collection " + workspaceCount, }; 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"); + Doc.AddDocToList(Doc.GetProto(Doc.UserDoc().myDocuments as Doc), "data", freeformDoc); + const mainDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myDocuments as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row"); const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`); mainDoc.contextMenuScripts = new List([toggleTheme!]); @@ -261,7 +261,7 @@ export class MainView extends React.Component { } // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) setTimeout(async () => { - const col = this.userDoc && await Cast(this.userDoc.optionalRightCollection, Doc); + const col = this.userDoc && await Cast(this.userDoc.rightSidebarCollection, Doc); col && Cast(col.data, listSpec(Doc)) && runInAction(() => MainViewNotifs.NotifsCol = col); }, 100); return true; @@ -504,8 +504,8 @@ export class MainView extends React.Component { return !this._flyoutTranslate ? (
    ) : (null); } - addButtonDoc = (doc: Doc) => Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", doc); - remButtonDoc = (doc: Doc) => Doc.RemoveDocFromList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", doc); + addButtonDoc = (doc: Doc) => Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc); + remButtonDoc = (doc: Doc) => Doc.RemoveDocFromList(Doc.UserDoc().dockedBtns as Doc, "data", doc); moveButtonDoc = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => this.remButtonDoc(doc) && addDocument(doc); buttonBarXf = () => { @@ -514,13 +514,13 @@ export class MainView extends React.Component { return new Transform(-translateX, -translateY, 1 / scale); } @computed get docButtons() { - const expandingBtns = Doc.UserDoc()?.expandingButtons; - if (expandingBtns instanceof Doc) { + const dockedBtns = Doc.UserDoc()?.dockedBtns; + if (dockedBtns instanceof Doc) { return
    + style={{ height: !dockedBtns.linearViewIsExpanded ? "42px" : undefined }} > void; @@ -140,10 +138,11 @@ export class OverlayView extends React.Component { } @computed get overlayDocs() { - if (!CurrentUserUtils.UserDocument) { + const userDocOverlays = Doc.UserDoc().myOverlayDocuments; + if (!userDocOverlays) { return (null); } - return CurrentUserUtils.UserDocument.overlays instanceof Doc && DocListCast(CurrentUserUtils.UserDocument.overlays.data).map(d => { + return userDocOverlays instanceof Doc && DocListCast(userDocOverlays.data).map(d => { setTimeout(() => d.inOverlay = true, 0); let offsetx = 0, offsety = 0; const onPointerMove = action((e: PointerEvent) => { @@ -195,7 +194,7 @@ export class OverlayView extends React.Component { addDocTab={returnFalse} pinToPres={emptyFunction} ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined}/> + ContainingCollectionDoc={undefined} />
    ; }); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index c74f5555b..5e77bc0bb 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -14,11 +14,9 @@ import { List } from '../../../new_fields/List'; import { FieldId } from "../../../new_fields/RefField"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { TraceMobx } from '../../../new_fields/util'; -import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; import { emptyFunction, returnOne, returnTrue, Utils, returnZero } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { Docs } from '../../documents/Documents'; -import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from "../../util/DragManager"; import { Scripting } from '../../util/Scripting'; @@ -376,8 +374,7 @@ export class CollectionDockingView extends React.Component this.setupGoldenLayout(), 1); - const userDoc = CurrentUserUtils.UserDocument; - userDoc && DocListCast((userDoc.workspaces as Doc).data).map(d => d.workspaceBrush = false); + DocListCast((Doc.UserDoc().myWorkspaces as Doc).data).map(d => d.workspaceBrush = false); this.props.Document.workspaceBrush = true; } this._ignoreStateChange = ""; @@ -544,9 +541,8 @@ export class CollectionDockingView extends React.Component { @action public static PinDoc(doc: Doc) { //add this new doc to props.Document - const curPres = Cast(CurrentUserUtils.UserDocument.curPresentation, Doc) as Doc; + const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; if (curPres) { const pinDoc = Doc.MakeAlias(doc); pinDoc.presentationTargetDoc = doc; @@ -698,7 +694,7 @@ export class DockedFrameRenderer extends React.Component { @action public static UnpinDoc(doc: Doc) { //add this new doc to props.Document - const curPres = Cast(CurrentUserUtils.UserDocument.curPresentation, Doc) as Doc; + const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; if (curPres) { const ind = DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)); ind !== -1 && Doc.RemoveDocFromList(curPres, "data", DocListCast(curPres.data)[ind]); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 1d1949c99..742a818bc 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -91,7 +91,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { public static SyncTimelineToPresentation(doc: Doc) { const fieldKey = Doc.LayoutFieldKey(doc); - doc[fieldKey + "-timelineCur"] = ComputedField.MakeFunction("(curPresentationItem()[this._pivotField || 'year'] || 0)"); + doc[fieldKey + "-timelineCur"] = ComputedField.MakeFunction("(activePresentationItem()[this._pivotField || 'year'] || 0)"); } specificMenu = (e: React.MouseEvent) => { const layoutItems: ContextMenuProps[] = []; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index c243d8f29..83e536167 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -6,10 +6,9 @@ import { observer } from "mobx-react"; import { Doc, DocListCast, Field, HeightSym, WidthSym, DataSym, Opt } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; -import { Document, listSpec, createSchema, makeInterface } from '../../../new_fields/Schema'; +import { Document, listSpec } from '../../../new_fields/Schema'; import { ComputedField, ScriptField } from '../../../new_fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../new_fields/Types'; -import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; import { emptyFunction, emptyPath, returnFalse, Utils, returnOne, returnZero, returnTransparent, returnTrue, simulateMouseClick } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from "../../documents/DocumentTypes"; @@ -195,7 +194,7 @@ class TreeView extends React.Component { })} onClick={() => { SelectionManager.DeselectAll(); - Doc.UserDoc().SelectedDocs = new List([this.props.document]); + Doc.UserDoc().activeSelection = new List([this.props.document]); return false; }} OnTab={undoBatch((shift?: boolean) => { @@ -691,14 +690,14 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as } onContextMenu = (e: React.MouseEvent): void => { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout - if (!e.isPropagationStopped() && this.props.Document === CurrentUserUtils.UserDocument.workspaces) { + if (!e.isPropagationStopped() && this.props.Document === Doc.UserDoc().myWorkspaces) { ContextMenu.Instance.addItem({ description: "Create Workspace", event: () => MainView.Instance.createNewWorkspace(), icon: "plus" }); ContextMenu.Instance.addItem({ description: "Delete Workspace", event: () => this.remove(this.props.Document), icon: "minus" }); e.stopPropagation(); e.preventDefault(); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); - } else if (!e.isPropagationStopped() && this.props.Document === CurrentUserUtils.UserDocument.recentlyClosed) { - ContextMenu.Instance.addItem({ description: "Clear All", event: () => CurrentUserUtils.UserDocument.recentlyClosed = new List(), icon: "plus" }); + } else if (!e.isPropagationStopped() && this.props.Document === Doc.UserDoc().myRecentlyClosed) { + ContextMenu.Instance.addItem({ description: "Clear All", event: () => Doc.UserDoc().myRecentlyClosed = new List(), icon: "plus" }); e.stopPropagation(); e.preventDefault(); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); @@ -739,14 +738,14 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as heroView._showTitle = "title"; heroView._showTitleHover = "titlehover"; - Doc.AddDocToList(Doc.UserDoc().expandingButtons as Doc, "data", + Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", Docs.Create.FontIconDocument({ title: "hero view", _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", dragFactory: heroView, removeDropProperties: new List(["dropAction"]), icon: "portrait", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), })); - Doc.AddDocToList(Doc.UserDoc().expandingButtons as Doc, "data", + Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", Docs.Create.FontIconDocument({ title: "detail view", _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", dragFactory: detailView, removeDropProperties: new List(["dropAction"]), icon: "file-alt", diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ca4ec7aff..196104fe0 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -305,7 +305,7 @@ export class DocumentView extends DocComponent(Docu self: this.rootDoc, thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey }, console.log); - if (this.props.Document !== Doc.UserDoc().undoBtn && this.props.Document !== Doc.UserDoc().redoBtn) { + if (this.props.Document !== Doc.UserDoc()["dockedBtn-undo"] && this.props.Document !== Doc.UserDoc()["dockedBtn-redo"]) { UndoManager.RunInBatch(func, "on click"); } else func(); } else if (this.Document["onClick-rawScript"] && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) {// bcz: hack? don't edit a script if you're clicking on a scripting box itself @@ -560,7 +560,7 @@ export class DocumentView extends DocComponent(Docu } static findTemplate(templateName: string, type: string, signature: string) { let docLayoutTemplate: Opt; - const iconViews = DocListCast(Cast(Doc.UserDoc()["icon-view-all"], Doc, null)?.data); + const iconViews = DocListCast(Cast(Doc.UserDoc()["template-icons"], 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); diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index e428e16da..80d043db1 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -49,7 +49,7 @@ export class PresBox extends ViewBoxBaseComponent @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); } @computed get currentIndex() { return NumCast(this.layoutDoc._itemIndex); } - updateCurrentPresentation = action(() => Doc.UserDoc().curPresentation = this.rootDoc); + updateCurrentPresentation = action(() => Doc.UserDoc().activePresentation = this.rootDoc); next = () => { this.updateCurrentPresentation(); @@ -253,14 +253,14 @@ export class PresBox extends ViewBoxBaseComponent updateMinimize = undoBatch(action((e: React.ChangeEvent, mode: CollectionViewType) => { if (BoolCast(this.layoutDoc.inOverlay) !== (mode === CollectionViewType.Invalid)) { if (this.layoutDoc.inOverlay) { - Doc.RemoveDocFromList((Doc.UserDoc().overlays as Doc), undefined, this.rootDoc); + Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc); CollectionDockingView.AddRightSplit(this.rootDoc); this.layoutDoc.inOverlay = false; } else { this.layoutDoc.x = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[0];// 500;//e.clientX + 25; this.layoutDoc.y = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[1];////e.clientY - 25; this.props.addDocTab?.(this.rootDoc, "close"); - Doc.AddDocToList((Doc.UserDoc().overlays as Doc), undefined, this.rootDoc); + Doc.AddDocToList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc); } } })); @@ -292,7 +292,7 @@ export class PresBox extends ViewBoxBaseComponent this.updateMinimize(e, StrCast(this.layoutDoc._viewType)); }); - childLayoutTemplate = () => this.layoutDoc._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc().presentationTemplate, Doc, null) : undefined; + childLayoutTemplate = () => this.layoutDoc._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc()["template-presentation"], Doc, null) : undefined; render() { const mode = StrCast(this.layoutDoc._viewType) as CollectionViewType; this.initializeViewAliases(this.childDocs, mode); diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index 5903a2ce9..295e82142 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -67,7 +67,7 @@ class Uploader extends React.Component { const field = await DocServer.GetRefField(res); let pending: Opt; if (field instanceof Doc) { - pending = await Cast(field.optionalRightCollection, Doc); + pending = await Cast(field.rightSidebarCollection, Doc); } if (pending) { this.status = "has pending docs"; diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index c87ac719c..73ebbb303 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -1,51 +1,38 @@ import React = require('react'); +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faEraser, faHighlighter, faLongArrowAltLeft, faMousePointer, faPenNib } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { computed, action, observable } from 'mobx'; -import { CurrentUserUtils } from '../server/authentication/models/current_user_utils'; -import { FieldValue, Cast, StrCast } from '../new_fields/Types'; -import { Doc, DocListCast } from '../new_fields/Doc'; +import { DocServer } from '../client/DocServer'; import { Docs } from '../client/documents/Documents'; -import { CollectionView } from '../client/views/collections/CollectionView'; -import { DocumentView } from '../client/views/nodes/DocumentView'; -import { emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue, returnZero } from '../Utils'; -import { Transform } from '../client/util/Transform'; -import { library } from '@fortawesome/fontawesome-svg-core'; -import { faPenNib, faHighlighter, faEraser, faMousePointer, faBreadSlice, faTrash, faCheck, faLongArrowAltLeft } from '@fortawesome/free-solid-svg-icons'; +import { DocumentManager } from '../client/util/DocumentManager'; +import RichTextMenu from '../client/util/RichTextMenu'; import { Scripting } from '../client/util/Scripting'; -import { CollectionFreeFormView } from '../client/views/collections/collectionFreeForm/CollectionFreeFormView'; +import { Transform } from '../client/util/Transform'; +import { CollectionView } from '../client/views/collections/CollectionView'; +import { DocumentDecorations } from '../client/views/DocumentDecorations'; import GestureOverlay from '../client/views/GestureOverlay'; import { InkingControl } from '../client/views/InkingControl'; -import { InkTool } from '../new_fields/InkField'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import "./MobileInterface.scss"; -import { SelectionManager } from '../client/util/SelectionManager'; -import { DateField } from '../new_fields/DateField'; -import { GestureUtils } from '../pen-gestures/GestureUtils'; -import { DocServer } from '../client/DocServer'; -import { DocumentDecorations } from '../client/views/DocumentDecorations'; -import { OverlayView } from '../client/views/OverlayView'; -import { DictationOverlay } from '../client/views/DictationOverlay'; -import SharingManager from '../client/util/SharingManager'; -import { PreviewCursor } from '../client/views/PreviewCursor'; -import { ContextMenu } from '../client/views/ContextMenu'; +import { DocumentView } from '../client/views/nodes/DocumentView'; import { RadialMenu } from '../client/views/nodes/RadialMenu'; -import PDFMenu from '../client/views/pdf/PDFMenu'; -import MarqueeOptionsMenu from '../client/views/collections/collectionFreeForm/MarqueeOptionsMenu'; -import GoogleAuthenticationManager from '../client/apis/GoogleAuthenticationManager'; -import { listSpec } from '../new_fields/Schema'; +import { PreviewCursor } from '../client/views/PreviewCursor'; +import { Doc, DocListCast, FieldResult } from '../new_fields/Doc'; import { Id } from '../new_fields/FieldSymbols'; -import { DocumentManager } from '../client/util/DocumentManager'; -import RichTextMenu from '../client/util/RichTextMenu'; +import { InkTool } from '../new_fields/InkField'; +import { listSpec } from '../new_fields/Schema'; +import { Cast, FieldValue } from '../new_fields/Types'; import { WebField } from "../new_fields/URLField"; -import { FieldResult } from "../new_fields/Doc"; -import { List } from '../new_fields/List'; +import { CurrentUserUtils } from '../server/authentication/models/current_user_utils'; +import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero } from '../Utils'; +import "./MobileInterface.scss"; library.add(faLongArrowAltLeft); @observer export default class MobileInterface extends React.Component { @observable static Instance: MobileInterface; - @computed private get userDoc() { return CurrentUserUtils.UserDocument; } + @computed private get userDoc() { return Doc.UserDoc(); } @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; } // @observable private currentView: "main" | "ink" | "upload" = "main"; private mainDoc: any = CurrentUserUtils.setupMobileDoc(this.userDoc); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index bcf0d1aec..8e8f0928c 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -865,6 +865,16 @@ export namespace Doc { return id; } + export function isDocPinned(doc: Doc) { + //add this new doc to props.Document + const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; + if (curPres) { + return DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)) !== -1; + } + return false; + } + + export async function addFieldEnumerations(doc: Opt, enumeratedFieldKey: string, enumerations: { title: string, _backgroundColor?: string, color?: string }[]) { let optionsCollection = await DocServer.GetRefField(enumeratedFieldKey); if (!(optionsCollection instanceof Doc)) { @@ -906,13 +916,13 @@ Scripting.addGlobal(function redo() { return UndoManager.Redo(); }); Scripting.addGlobal(function DOC(id: string) { console.log("Can't parse a document id in a script"); return "invalid"; }); Scripting.addGlobal(function assignDoc(doc: Doc, field: string, id: string) { return Doc.assignDocToField(doc, field, id); }); Scripting.addGlobal(function docCast(doc: FieldResult): any { return DocCastAsync(doc); }); -Scripting.addGlobal(function curPresentationItem() { - const curPres = Doc.UserDoc().curPresentation as Doc; +Scripting.addGlobal(function activePresentationItem() { + const curPres = Doc.UserDoc().activePresentation as Doc; return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)]; }); -Scripting.addGlobal(function selectDoc(doc: any) { Doc.UserDoc().SelectedDocs = new List([doc]); }); +Scripting.addGlobal(function selectDoc(doc: any) { Doc.UserDoc().activeSelection = new List([doc]); }); Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) { - const docs = DocListCast(Doc.UserDoc().SelectedDocs). + const docs = DocListCast(Doc.UserDoc().activeSelection). filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.DOCHOLDER && d.type !== DocumentType.KVP && (!excludeCollections || d.type !== DocumentType.COL || !Cast(d.data, listSpec(Doc), null))); return docs.length ? new List(docs) : prevValue; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 3d68d8425..a2f016f94 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -30,7 +30,7 @@ export class CurrentUserUtils { public static get MainDocId() { return this.mainDocId; } public static set MainDocId(id: string | undefined) { this.mainDocId = id; } @computed public static get UserDocument() { return Doc.UserDoc(); } - @computed public static get ActivePen() { return Doc.UserDoc().activePen instanceof Doc && (Doc.UserDoc().activePen as Doc).pen as Doc; } + @computed public static get ActivePen() { return Doc.UserDoc().activePen instanceof Doc && (Doc.UserDoc().activePen as Doc).inkPen as Doc; } @observable public static GuestTarget: Doc | undefined; @observable public static GuestWorkspace: Doc | undefined; @@ -84,10 +84,12 @@ export class CurrentUserUtils { 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", + title: "Template Item Creators", _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 }), })); + } else { + DocListCast(Cast(doc["template-buttons"], Doc, null)?.data); // prefetch templates } return doc["template-buttons"] as Doc; } @@ -114,9 +116,10 @@ export class CurrentUserUtils { 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 })); + } else { + DocListCast(Cast(doc.noteTypes, Doc, null)?.data); // prefetch templates } - // 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; } @@ -135,29 +138,31 @@ export class CurrentUserUtils { // setup templates for different document types when they are iconified from Document Decorations static setupDefaultIconTemplates(doc: Doc) { - if (doc["icon-view"] === undefined) { + if (doc["template-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); + doc["template-icon-view"] = new PrefetchProxy(iconView); } - if (doc["icon-view-img"] === undefined) { + if (doc["template-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); + doc["template-icon-view-img"] = new PrefetchProxy(iconImageView); } - if (doc["icon-view-col"] === undefined) { + if (doc["template-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); + doc["template-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 })); + if (doc["template-icons"] === undefined) { + doc["template-icons"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, doc["template-icon-view-col"] as Doc], { title: "icon templates", _height: 75 })); + } else { + DocListCast(Cast(doc["template-icons"], Doc, null)?.data); // prefetch templates } - return doc["icon-view-all"] as Doc; + return doc["template-icons"] as Doc; } static creatorBtnDescriptors(doc: Doc): { @@ -180,15 +185,15 @@ export class CurrentUserUtils { { 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: doc.emptyPresentation as Doc }, + { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = 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' }, - // { 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: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + // { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + // { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "pink", activePen: doc }, + // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.inkPen = this;', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "white", activePen: doc }, { 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()" }, @@ -198,7 +203,7 @@ export class CurrentUserUtils { // 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); + const dragCreatorSet = await Cast(doc.myItemCreators, Doc, null); if (dragCreatorSet) { const dragCreators = await Cast(dragCreatorSet.data, listSpec(Doc)); if (dragCreators) { @@ -223,25 +228,25 @@ export class CurrentUserUtils { })); if (dragCreatorSet === undefined) { - doc.dragCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, { - title: "Draggable Items", _showTitle: "title", _xMargin: 0, + doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, { + title: "Standard Item Creators", _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)); + creatorBtns.forEach(nb => Doc.AddDocToList(doc.myItemCreators as Doc, "data", nb)); } - return doc.dragCreators as Doc; + return doc.myItemCreators as Doc; } static setupMobileButtons(doc: Doc, buttons?: string[]) { const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ { title: "record", icon: "microphone", ignoreClick: true, click: "FILL" }, - { 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 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: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc }, + { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "pink", activePen: doc }, + { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.inkPen = this;', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "white", activePen: doc }, + // { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "red", activePen: doc }, { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload, onSwitchMobileUpload);', backgroundColor: "orange" }, // { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" }, ]; @@ -255,11 +260,11 @@ export class CurrentUserUtils { static setupThumbButtons(doc: Doc) { const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, pointerDown?: string, pointerUp?: string, ischecked?: string, clipboard?: Doc, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ - { title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, - { title: "use highlighter", icon: "highlighter", pointerUp: "resetPen()", pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, - { title: "notepad", icon: "clipboard", pointerUp: "GestureOverlay.Instance.closeFloatingDoc()", pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)', clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300 }), backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, - { title: "interpret text", icon: "font", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('inktotext')", backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, - { title: "ignore gestures", icon: "signature", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('ignoregesture')", backgroundColor: "green", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, + { title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + { title: "use highlighter", icon: "highlighter", pointerUp: "resetPen()", pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + { title: "notepad", icon: "clipboard", pointerUp: "GestureOverlay.Instance.closeFloatingDoc()", pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)', clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300 }), backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + { title: "interpret text", icon: "font", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('inktotext')", backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + { title: "ignore gestures", icon: "signature", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('ignoregesture')", backgroundColor: "green", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, ]; return docProtoData.map(data => Docs.Create.FontIconDocument({ _nativeWidth: 10, _nativeHeight: 10, _width: 10, _height: 10, title: data.title, icon: data.icon, @@ -316,25 +321,25 @@ export class CurrentUserUtils { const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc); const templateBtns = CurrentUserUtils.setupUserTemplateButtons(doc); - if (doc.allCreators === undefined) { - doc.allCreators = new PrefetchProxy(Docs.Create.StackingDocument([creatorBtns, templateBtns], { + if (doc.myCreators === undefined) { + doc.myCreators = 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 - if (doc.colorPicker === undefined) { + if (doc.myColorPicker === 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); + doc.myColorPicker = new PrefetchProxy(color); } 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], { + sourcePanel: new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker 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, @@ -347,39 +352,39 @@ export class CurrentUserUtils { static setupWorkspaces(doc: Doc) { // setup workspaces library item - if (doc.worspaces === undefined) { - doc.workspaces = new PrefetchProxy(Docs.Create.TreeDocument([], { + if (doc.myWorkspaces === undefined) { + doc.myWorkspaces = 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.myWorkspaces as Doc).contextMenuScripts = new List([newWorkspace!]); + (doc.myWorkspaces as Doc).contextMenuLabels = new List(["Create New Workspace"]); - return doc.workspaces as Doc; + return doc.myWorkspaces as Doc; } static setupDocumentCollection(doc: Doc) { - if (doc.documents === undefined) { - doc.documents = new PrefetchProxy(Docs.Create.TreeDocument([], { + if (doc.myDocuments === undefined) { + doc.myDocuments = new PrefetchProxy(Docs.Create.TreeDocument([], { title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, })); } - return doc.documents as Doc; + return doc.myDocuments as Doc; } static setupRecentlyClosed(doc: Doc) { // setup Recently Closed library item - if (doc.recentlyClosed === undefined) { - doc.recentlyClosed = new PrefetchProxy(Docs.Create.TreeDocument([], { + if (doc.myRecentlyClosed === undefined) { + doc.myRecentlyClosed = 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)); + PromiseValue(Cast(doc.myRecentlyClosed, 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"]); + (doc.myRecentlyClosed as Doc).contextMenuScripts = new List([clearAll!]); + (doc.myRecentlyClosed as Doc).contextMenuLabels = new List(["Clear All"]); - return doc.recentlyClosed as Doc; + return doc.myRecentlyClosed 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) { @@ -456,48 +461,48 @@ export class CurrentUserUtils { })) 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) { - 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 + static setupDockedButtons(doc: Doc) { + if (doc["dockedBtn-pen"] === undefined) { + doc["dockedBtn-pen"] = CurrentUserUtils.ficon({ + onClick: ScriptField.MakeScript("activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)"), + author: "systemTemplates", title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.inkPen, this)`), activePen: doc }); } - if (doc.undoBtn === undefined) { - doc.undoBtn = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" }); + if (doc["dockedBtn-undo"] === undefined) { + doc["dockedBtn-undo"] = 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["dockedBtn-redo"] === undefined) { + doc["dockedBtn-redo"] = 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]); + if (doc.dockedBtns === undefined) { + doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc, doc["dockedBtn-pen"] as Doc]); } } // sets up the default set of documents to be shown in the Overlay layer static setupOverlays(doc: Doc) { - if (doc.overlays === undefined) { - doc.overlays = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "Overlays", backgroundColor: "#aca3a6" })); + if (doc.myOverlayDocuments === undefined) { + doc.myOverlayDocuments = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "overlay documents", backgroundColor: "#aca3a6" })); } } // the initial presentation Doc to use static setupDefaultPresentation(doc: Doc) { - if (doc.presentationTemplate === undefined) { - doc.presentationTemplate = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ + if (doc["template-presentation"] === undefined) { + doc["template-presentation"] = 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(), { + if (doc.activePresentation === undefined) { + doc.activePresentation = Docs.Create.PresDocument(new List(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" }); } } - static setupMobileUploads(doc: Doc) { - if (doc.optionalRightCollection === undefined) { - doc.optionalRightCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "New mobile uploads" })); + static setupRightSidebar(doc: Doc) { + if (doc.rightSidebarCollection === undefined) { + doc.rightSidebarCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Right Sidebar" })); } } @@ -532,29 +537,19 @@ export class CurrentUserUtils { 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.setupRightSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing CurrentUserUtils.setupOverlays(doc); // documents in overlay layer - CurrentUserUtils.setupExpandingButtons(doc); // the bottom bar of font icons + CurrentUserUtils.setupDockedButtons(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(); + doc.globalLinkDatabase = 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 }); + doc["dockedBtn-undo"] && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc["dockedBtn-undo"] as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); + doc["dockedBtn-redo"] && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc["dockedBtn-redo"] as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); return doc; } - - public static IsDocPinned(doc: Doc) { - //add this new doc to props.Document - const curPres = Cast(CurrentUserUtils.UserDocument.curPresentation, Doc) as Doc; - if (curPres) { - return DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)) !== -1; - } - return false; - } - public static async loadCurrentUser() { return rp.get(Utils.prepend("/getCurrentUser")).then(response => { if (response) { -- cgit v1.2.3-70-g09d2 From 821bd7bb1b2a59459c63ecfbe9c513e5f36a7e43 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 20 Apr 2020 01:39:15 -0400 Subject: fixed runtime errors for AntimodeMenu and from current_user_utils not initializing properly --- src/client/util/RichTextMenu.tsx | 8 ++++---- src/client/views/AntimodeMenu.tsx | 21 +++++++++++++-------- src/client/views/collections/CollectionTreeView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../authentication/models/current_user_utils.ts | 13 +++++++------ 5 files changed, 26 insertions(+), 20 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/util/RichTextMenu.tsx b/src/client/util/RichTextMenu.tsx index 3f0ec7aa5..4a9a4c10f 100644 --- a/src/client/util/RichTextMenu.tsx +++ b/src/client/util/RichTextMenu.tsx @@ -445,8 +445,8 @@ export default class RichTextMenu extends AntimodeMenu { } const button = - ; const dropdownContent = @@ -790,11 +790,11 @@ export default class RichTextMenu extends AntimodeMenu {
    {this.getDragger()}
    diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx index fba2fb5c6..f810361c6 100644 --- a/src/client/views/AntimodeMenu.tsx +++ b/src/client/views/AntimodeMenu.tsx @@ -16,7 +16,8 @@ export default abstract class AntimodeMenu extends React.Component { @observable protected _top: number = -300; @observable protected _left: number = -300; @observable protected _opacity: number = 1; - @observable protected _transition: string = "opacity 0.5s"; + @observable protected _transitionProperty: string = "opacity"; + @observable protected _transitionDuration: string = "0.5s"; @observable protected _transitionDelay: string = ""; @observable protected _canFade: boolean = true; @@ -34,7 +35,7 @@ export default abstract class AntimodeMenu extends React.Component { */ public jumpTo = (x: number, y: number, forceJump: boolean = false) => { if (!this.Pinned || forceJump) { - this._transition = this._transitionDelay = ""; + this._transitionProperty = this._transitionDuration = this._transitionDelay = ""; this._opacity = 1; this._left = x; this._top = y; @@ -49,14 +50,16 @@ export default abstract class AntimodeMenu extends React.Component { public fadeOut = (forceOut: boolean) => { if (!this.Pinned) { if (this._opacity === 0.2) { - this._transition = "opacity 0.1s"; + this._transitionProperty = "opacity"; + this._transitionDuration = "0.1s"; this._transitionDelay = ""; this._opacity = 0; this._left = this._top = -300; } if (forceOut) { - this._transition = ""; + this._transitionProperty = ""; + this._transitionDuration = ""; this._transitionDelay = ""; this._opacity = 0; this._left = this._top = -300; @@ -67,7 +70,8 @@ export default abstract class AntimodeMenu extends React.Component { @action protected pointerLeave = (e: React.PointerEvent) => { if (!this.Pinned && this._canFade) { - this._transition = "opacity 0.5s"; + this._transitionProperty = "opacity"; + this._transitionDuration = "0.5s"; this._transitionDelay = "1s"; this._opacity = 0.2; setTimeout(() => this.fadeOut(false), 3000); @@ -76,7 +80,8 @@ export default abstract class AntimodeMenu extends React.Component { @action protected pointerEntered = (e: React.PointerEvent) => { - this._transition = "opacity 0.1s"; + this._transitionProperty = "opacity"; + this._transitionDuration = "0.1s"; this._transitionDelay = ""; this._opacity = 1; } @@ -133,7 +138,7 @@ export default abstract class AntimodeMenu extends React.Component { protected getElement(buttons: JSX.Element[]) { return (
    + style={{ left: this._left, top: this._top, opacity: this._opacity, transitionProperty: this._transitionProperty, transitionDuration: this._transitionDuration, transitionDelay: this._transitionDelay }}> {buttons}
    @@ -143,7 +148,7 @@ export default abstract class AntimodeMenu extends React.Component { protected getElementWithRows(rows: JSX.Element[], numRows: number, hasDragger: boolean = true) { return (
    + style={{ left: this._left, top: this._top, opacity: this._opacity, transitionProperty: this._transitionProperty, transitionDuration: this._transitionDuration, transitionDelay: this._transitionDelay, height: "auto" }}> {rows} {hasDragger ?
    : <>}
    diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 83e536167..011e07287 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -650,7 +650,7 @@ export type collectionTreeViewProps = { }; @observer -export class CollectionTreeView extends CollectionSubView(Document, undefined as any as collectionTreeViewProps) { +export class CollectionTreeView extends CollectionSubView>(Document) { private treedropDisposer?: DragManager.DragDropDisposer; private _mainEle?: HTMLDivElement; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 87cf716e5..d2106808e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -75,7 +75,7 @@ export type collectionFreeformViewProps = { }; @observer -export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, undefined as any as collectionFreeformViewProps) { +export class CollectionFreeFormView extends CollectionSubView>(PanZoomDocument) { private _lastX: number = 0; private _lastY: number = 0; private _downX: number = 0; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index a2f016f94..85938e026 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -536,12 +536,13 @@ export class CurrentUserUtils { 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.setupRightSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing - CurrentUserUtils.setupOverlays(doc); // documents in overlay layer - CurrentUserUtils.setupDockedButtons(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 + this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon + this.setupDocTemplates(doc); // sets up the template menu of templates + this.setupRightSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing + this.setupOverlays(doc); // documents in overlay layer + this.setupDockedButtons(doc); // the bottom bar of font icons + this.setupDefaultPresentation(doc); // presentation that's initially triggered + await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels doc.globalLinkDatabase = 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 -- cgit v1.2.3-70-g09d2 From feb43b4bf769575766825593269b97f46536dd72 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 20 Apr 2020 11:48:57 -0400 Subject: fixed ctrl-enter editing of treeviews. --- src/client/views/collections/CollectionTreeView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 011e07287..34f0f2313 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -189,7 +189,7 @@ class TreeView extends React.Component { Doc.SetInPlace(this.props.document, key, value, false); const doc = Docs.Create.FreeformDocument([], { title: "-", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); Doc.SetInPlace(this.props.document, "editTitle", undefined, false); - Doc.SetInPlace(this.props.document, "editTitle", true, false); + Doc.SetInPlace(doc, "editTitle", true, false); return this.props.addDocument(doc); })} onClick={() => { -- cgit v1.2.3-70-g09d2 From 49ebcb56488669c1f416c583a9b8c7914e5b6d34 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 20 Apr 2020 16:23:39 -0400 Subject: fixed moving documents in tree views --- src/client/util/DragManager.ts | 2 +- src/client/views/collections/CollectionTreeView.tsx | 13 +++++++------ src/server/authentication/models/current_user_utils.ts | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 3e9a5b63a..3ea030171 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -19,7 +19,7 @@ import { DateField } from "../../new_fields/DateField"; import { DocumentView } from "../views/nodes/DocumentView"; import { UndoManager } from "./UndoManager"; -export type dropActionType = "place" | "alias" | "copy" | undefined; +export type dropActionType = "alias" | "copy" | "move" | undefined; // undefined = move export function SetupDrag( _reference: React.RefObject, docFunc: () => Doc | Promise | undefined, diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 34f0f2313..d8e2c8841 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -228,7 +228,8 @@ class TreeView extends React.Component { addDoc = (doc: Doc) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc) || addDoc(doc); } const movedDocs = (de.complete.docDragData.treeViewId === this.props.treeViewId[Id] ? de.complete.docDragData.draggedDocuments : de.complete.docDragData.droppedDocuments); - return ((de.complete.docDragData.dropAction && (de.complete.docDragData.treeViewId !== this.props.treeViewId[Id])) || de.complete.docDragData.userDropAction) ? + const move = de.complete.docDragData.dropAction === "move" || de.complete.docDragData.dropAction; + return ((!move && (de.complete.docDragData.treeViewId !== this.props.treeViewId[Id])) || de.complete.docDragData.userDropAction) ? de.complete.docDragData.droppedDocuments.reduce((added, d) => addDoc(d) || added, false) : de.complete.docDragData.moveDocument ? movedDocs.reduce((added, d) => de.complete.docDragData?.moveDocument?.(d, undefined, addDoc) || added, false) @@ -335,7 +336,7 @@ class TreeView extends React.Component { {!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, - this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform, + StrCast(this.props.document.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen, [...this.props.renderedIds, this.props.document[Id]], this.props.libraryPath, this.props.onCheckedClick, this.props.onChildClick, this.props.ignoreFields)} ; @@ -456,7 +457,7 @@ class TreeView extends React.Component { pinToPres={emptyFunction} onClick={this.props.onChildClick || editTitle} dropAction={this.props.dropAction} - moveDocument={this.props.moveDocument} + moveDocument={this.move} removeDocument={this.removeDoc} ScreenToLocalTransform={this.getTransform} ContentScaling={returnOne} @@ -472,7 +473,7 @@ class TreeView extends React.Component { bringToFront={emptyFunction} dontRegisterView={BoolCast(this.props.treeViewId.dontRegisterChildren)} ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} + ContainingCollectionDoc={this.props.containingCollection} />}
    {this.props.treeViewHideHeaderFields() ? (null) : headerElements} @@ -657,7 +658,7 @@ export class CollectionTreeView extends CollectionSubView { - this.treedropDisposer && this.treedropDisposer(); + this.treedropDisposer?.(); if (this._mainEle = ele) { this.treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this)); } @@ -665,7 +666,7 @@ export class CollectionTreeView extends CollectionSubView Date: Mon, 20 Apr 2020 16:37:13 -0400 Subject: fixed ctrl-enter on text box title. fixed min-width of tree view titles. --- src/client/views/collections/CollectionTreeView.scss | 1 + src/client/views/collections/CollectionTreeView.tsx | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 1e59c493f..a00bb6bfb 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -82,6 +82,7 @@ text-overflow: ellipsis; white-space: pre-wrap; overflow: hidden; + min-width: 10px; // width:100%;//width: max-content; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d8e2c8841..f589c2c76 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -487,11 +487,15 @@ class TreeView extends React.Component { return
  • { - e.stopPropagation(); - e.preventDefault(); + if (this.props.active(true)) { + e.stopPropagation(); + e.preventDefault(); + } }} onPointerDown={e => { - e.stopPropagation(); - e.preventDefault(); + if (this.props.active(true)) { + e.stopPropagation(); + e.preventDefault(); + } }} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}> {this.renderBullet} {this.renderTitle} @@ -810,6 +814,7 @@ export class CollectionTreeView extends CollectionSubView([Templates.Title.Layout]) }); EditableView.loadId = doc[Id]; + Doc.SetInPlace(doc, "editTitle", true, false); this.addDoc(doc, childDocs.length ? childDocs[0] : undefined, true); })} />)} {this.props.Document.allowClear ? this.renderClearButton : (null)} -- cgit v1.2.3-70-g09d2 From 72f614f023a4bac6a2f0b63a1b1a16e6f4545c7a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 23 Apr 2020 00:53:08 -0400 Subject: fixed browser back after link navigation. simplified menus more. fixed jitter mode to be seeded. fixed menu gear for collections. . --- src/client/util/History.ts | 6 +++- src/client/util/ProsemirrorExampleTransfer.ts | 4 +-- src/client/views/DocumentDecorations.tsx | 6 +++- .../views/collections/CollectionDockingView.tsx | 6 +++- .../views/collections/CollectionStackingView.tsx | 2 +- .../views/collections/CollectionTimeView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 4 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 21 +++++------ src/client/views/nodes/AudioBox.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 9 +++-- src/client/views/nodes/DocumentBox.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 41 ++++++++++++++++++++-- src/client/views/nodes/KeyValueBox.tsx | 23 ++++++++---- src/client/views/nodes/LinkAnchorBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/nodes/ScreenshotBox.tsx | 2 +- src/client/views/nodes/SliderBox.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 2 +- 20 files changed, 103 insertions(+), 39 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/util/History.ts b/src/client/util/History.ts index 545e8acb4..2c53d7e52 100644 --- a/src/client/util/History.ts +++ b/src/client/util/History.ts @@ -40,8 +40,12 @@ export namespace HistoryUtil { // } } + let _lastStatePush = 0; export function pushState(state: ParsedUrl) { - history.pushState(state, "", createUrl(state)); + if (Date.now() - _lastStatePush > 1000) { + history.pushState(state, "", createUrl(state)); + } + _lastStatePush = Date.now(); } export function replaceState(state: ParsedUrl) { diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts index 42247f177..680f48f70 100644 --- a/src/client/util/ProsemirrorExampleTransfer.ts +++ b/src/client/util/ProsemirrorExampleTransfer.ts @@ -154,7 +154,7 @@ export default function buildKeymap>(schema: S, props: any const originalDoc = layoutDoc.rootDocument || layoutDoc; if (originalDoc instanceof Doc) { const newDoc = Docs.Create.TextDocument("", { - title: "", layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine), + layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine), x: NumCast(originalDoc.x), y: NumCast(originalDoc.y) + NumCast(originalDoc._height) + 10, _width: NumCast(layoutDoc._width), _height: NumCast(layoutDoc._height) }); FormattedTextBox.SelectOnLoad = newDoc[Id]; @@ -172,7 +172,7 @@ export default function buildKeymap>(schema: S, props: any const originalDoc = layoutDoc.rootDocument || layoutDoc; if (force || props.Document._singleLine) { const newDoc = Docs.Create.TextDocument("", { - title: "", layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine), + layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine), x: NumCast(originalDoc.x) + NumCast(originalDoc._width) + 10, y: NumCast(originalDoc.y), _width: NumCast(layoutDoc._width), _height: NumCast(layoutDoc._height) }); FormattedTextBox.SelectOnLoad = newDoc[Id]; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 43c7751fa..6e699bc68 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -134,7 +134,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @action onSettingsClick = (e: PointerEvent): void => { if (e.button === 0 && !e.altKey && !e.ctrlKey) { let child = SelectionManager.SelectedDocuments()[0].ContentDiv!.children[0]; - while (child.children.length) child = child.children[0]; + while (child.children.length) { + const next = Array.from(child.children).find(c => !c.className.includes("collectionViewChrome")); + if (next) child = next; + else break; + } simulateMouseClick(child, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); } } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 5e77bc0bb..0d859c3f1 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -29,6 +29,7 @@ import "./CollectionDockingView.scss"; import { SubCollectionViewProps } from "./CollectionSubView"; import { DockingViewButtonSelector } from './ParentDocumentSelector'; import React = require("react"); +import { CollectionViewType } from './CollectionView'; library.add(faFile); const _global = (window /* browser */ || global /* node */) as any; @@ -93,6 +94,9 @@ export class CollectionDockingView extends React.Component { addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => { SelectionManager.DeselectAll(); - if (doc.dockingConfig) { + if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === "layout") { return MainView.Instance.openWorkspace(doc); } else if (location === "onRight") { return CollectionDockingView.AddRightSplit(doc, libraryPath); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index b15649d83..24a3119cc 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -397,7 +397,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { if (!e.isPropagationStopped()) { const subItems: ContextMenuProps[] = []; subItems.push({ description: `${this.props.Document.fillColumn ? "Variable Size" : "Autosize"} Column`, event: () => this.props.Document.fillColumn = !this.props.Document.fillColumn, icon: "plus" }); - ContextMenu.Instance.addItem({ description: "Stacking Options ...", subitems: subItems, icon: "eye" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" }); } } diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 742a818bc..06ebf6d2d 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -102,7 +102,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { doc._forceRenderEngine = undefined; }, icon: "compress-arrows-alt" }); layoutItems.push({ description: "Sync with presentation", event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: "compress-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Pivot/Time Options ...", subitems: layoutItems, icon: "eye" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" }); } @computed get _allFacets() { const facets = new Set(); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index f589c2c76..a052d045c 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -711,7 +711,7 @@ export class CollectionTreeView extends CollectionSubView this.props.Document.treeViewPreventOpen = !this.props.Document.treeViewPreventOpen, icon: "paint-brush" }); layoutItems.push({ description: (this.props.Document.treeViewHideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.props.Document.treeViewHideHeaderFields = !this.props.Document.treeViewHideHeaderFields, icon: "paint-brush" }); layoutItems.push({ description: (this.props.Document.treeViewHideTitle ? "Show" : "Hide") + " Title", event: () => this.props.Document.treeViewHideTitle = !this.props.Document.treeViewHideTitle, icon: "paint-brush" }); - ContextMenu.Instance.addItem({ description: "Treeview Options ...", subitems: layoutItems, icon: "eye" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" }); } ContextMenu.Instance.addItem({ description: "Buxton Layout", icon: "eye", event: () => { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index ade54f2c9..4f1242c33 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -229,7 +229,7 @@ export class CollectionView extends Touchable { return newRendition; }, false); - const existing = ContextMenu.Instance.findByDescription("Layout..."); + const existing = ContextMenu.Instance.findByDescription("Options..."); const layoutItems = existing && "subitems" in existing ? existing.subitems : []; layoutItems.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }); if (this.props.Document.childLayout instanceof Doc) { @@ -240,7 +240,7 @@ export class CollectionView extends Touchable { } layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" }); - !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" }); + !existing && ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "hand-point-right" }); const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3b5101a4d..55e55e56c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1048,16 +1048,17 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.props.children && this.props.annotationsKey) return; - const layoutItems: ContextMenuProps[] = []; - - layoutItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); - layoutItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); - layoutItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); - layoutItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); - layoutItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }); + const options = ContextMenu.Instance.findByDescription("Options..."); + const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : []; + + optionItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); + optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); + optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); + optionItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); + optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }); // layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" }); - layoutItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" }); - layoutItems.push({ + optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" }); + optionItems.push({ description: "Import document", icon: "upload", event: ({ x, y }) => { const input = document.createElement("input"); input.type = "file"; @@ -1085,7 +1086,7 @@ export class CollectionFreeFormView extends CollectionSubView { diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 8f40ea2be..6ff6d1b42 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -162,7 +162,7 @@ export class AudioBox extends ViewBoxBaseComponent this.layoutDoc.playOnSelect = !this.layoutDoc.playOnSelect, icon: "expand-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Audio Funcs...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } stopRecording = action(() => { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 3a7e005ac..615b05e43 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,4 +1,3 @@ -import anime from "animejs"; import { computed, IReactionDisposer, observable, reaction, trace } from "mobx"; import { observer } from "mobx-react"; import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; @@ -29,8 +28,14 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { @observer export class CollectionFreeFormDocumentView extends DocComponent(PositionDocument) { @observable _animPos: number[] | undefined = undefined; + random(min: number, max: number) { // min should not be equal to max + const mseed = Math.abs(this.X * this.Y); + const seed = (mseed * 9301 + 49297) % 233280; + var rnd = seed / 233280; + return min + rnd * (max - min); + } get displayName() { return "CollectionFreeFormDocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive - get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${anime.random(-1, 1) * this.props.jitterRotation}deg)`; } + get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${this.random(-1, 1) * this.props.jitterRotation}deg)`; } get X() { return this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); } get Y() { return this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); } get ZInd() { return this.dataProvider ? this.dataProvider.zIndex : (this.Document.zIndex || 0); } diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx index ac562f19a..7583aa070 100644 --- a/src/client/views/nodes/DocumentBox.tsx +++ b/src/client/views/nodes/DocumentBox.tsx @@ -45,7 +45,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent Doc.GetProto(this.props.Document).excludeCollections = !this.props.Document.excludeCollections, icon: "expand-arrows-alt" }); funcs.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }); - ContextMenu.Instance.addItem({ description: "DocumentBox Funcs...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } @computed get contentDoc() { return (this.props.Document.isTemplateDoc || this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document)); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a19ba6506..cab7b965a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -741,7 +741,7 @@ export class DocumentView extends DocComponent(Docu const existingOnClick = cm.findByDescription("OnClick..."); const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" }); - onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(this, "${this.props.Document.layoutKey}")`), icon: "window-restore" }); + onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.props.Document.layoutKey}")`), icon: "window-restore" }); onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" }); onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" }); onClicks.push({ description: this.Document.isLinkButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" }); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 2c89d53d8..1329f7dcf 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -13,7 +13,7 @@ import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from " import { ReplaceStep } from 'prosemirror-transform'; import { EditorView } from "prosemirror-view"; import { DateField } from '../../../new_fields/DateField'; -import { DataSym, Doc, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; +import { DataSym, Doc, DocListCastAsync, Field, HeightSym, Opt, WidthSym, DocListCast } from "../../../new_fields/Doc"; import { documentSchema } from '../../../new_fields/documentSchemas'; import { Id } from '../../../new_fields/FieldSymbols'; import { InkTool } from '../../../new_fields/InkField'; @@ -48,6 +48,7 @@ import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './Format import React = require("react"); import { PrefetchProxy } from '../../../new_fields/Proxy'; import { makeTemplate } from '../../util/DropConverter'; +import { DocumentView } from './DocumentView'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -396,6 +397,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null); } specificContextMenu = (e: React.MouseEvent): void => { + const cm = ContextMenu.Instance; + const funcs: ContextMenuProps[] = []; this.props.Document.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document), icon: "eye" }); funcs.push({ description: "Reset Default Layout", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); @@ -407,10 +410,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }); funcs.push({ description: "Toggle Single Line", event: () => this.props.Document._singleLine = !this.props.Document._singleLine, icon: "expand-arrows-alt" }); funcs.push({ description: "Toggle Sidebar", event: () => this.props.Document._showSidebar = !this.props.Document._showSidebar, icon: "expand-arrows-alt" }); - funcs.push({ description: "Toggle Audio", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Dictation Icon", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" }); funcs.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" }); + + const highlighting: ContextMenuProps[] = []; ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option => - funcs.push({ + highlighting.push({ description: (FormattedTextBox._highlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => { e.stopPropagation(); if (FormattedTextBox._highlights.indexOf(option) === -1) { @@ -421,8 +426,38 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.updateHighlights(); }, icon: "expand-arrows-alt" })); + funcs.push({ description: "highlighting...", subitems: highlighting, icon: "hand-point-right" }); ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); + + const change = cm.findByDescription("Change Perspective..."); + const changeItems: ContextMenuProps[] = change && "subitems" in change ? change.subitems : []; + + const noteTypesDoc = Cast(Doc.UserDoc().noteTypes, Doc, null); + const noteTypes = DocListCast(noteTypesDoc?.data); + noteTypes.forEach(note => { + changeItems.push({ + description: StrCast(note.title), event: () => { + Doc.setNativeView(this.props.Document); + DocumentView.makeCustomViewClicked(this.rootDoc, Docs.Create.TreeDocument, StrCast(note.title), note); + }, icon: "eye" + }) + }); + changeItems.push({ description: "FreeForm", event: () => DocumentView.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), icon: "eye" }) + !change && cm.addItem({ description: "Change Perspective...", subitems: changeItems, icon: "external-link-alt" }); + + const open = cm.findByDescription("Open New Perspective..."); + const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; + + openItems.push({ + description: "FreeForm", event: () => { + const alias = Doc.MakeAlias(this.rootDoc); + DocumentView.makeCustomViewClicked(alias, Docs.Create.FreeformDocument, "freeform"); + this.props.addDocTab(alias, "onRight"); + }, icon: "eye" + }) + !open && cm.addItem({ description: "Open New Perspective...", subitems: openItems, icon: "external-link-alt" }); + } recordDictation = () => { diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 7aad6f90e..2970674a2 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -16,6 +16,8 @@ import { FieldView, FieldViewProps } from './FieldView'; import "./KeyValueBox.scss"; import { KeyValuePair } from "./KeyValuePair"; import React = require("react"); +import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from "../ContextMenuItem"; export type KVPScript = { script: CompiledScript; @@ -34,11 +36,7 @@ export class KeyValueBox extends React.Component { @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); } - get fieldDocToLayout() { return this.props.fieldKey ? FieldValue(Cast(this.props.Document[this.props.fieldKey], Doc)) : this.props.Document; } - - constructor(props: FieldViewProps) { - super(props); - } + get fieldDocToLayout() { return this.props.fieldKey ? Cast(this.props.Document[this.props.fieldKey], Doc, null) : this.props.Document; } @action onEnterKey = (e: React.KeyboardEvent): void => { @@ -234,13 +232,26 @@ export class KeyValueBox extends React.Component { return new Doc; } + specificContextMenu = (e: React.MouseEvent): void => { + const cm = ContextMenu.Instance; + const open = cm.findByDescription("Change Perspective..."); + const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; + openItems.push({ + description: "Default Perspective", event: () => { + this.props.addDocTab(this.fieldDocToLayout, "inTab"); + this.props.addDocTab(this.props.Document, "close"); + }, icon: "image" + }); + !open && cm.addItem({ description: "Change Perspective...", subitems: openItems, icon: "external-link-alt" }); + } + render() { const dividerDragger = this.splitPercentage === 0 ? (null) :
    ; - return (
    + return (
    diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 8e3c15908..eb647d0e4 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -109,7 +109,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent this.openLinkEditor(e), icon: "eye" }); funcs.push({ description: "Toggle Always Show Link", event: () => this.props.Document.linkDisplay = !this.props.Document.linkDisplay, icon: "eye" }); - ContextMenu.Instance.addItem({ description: "Link Funcs...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } render() { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 6db36e43c..3712c648e 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -210,7 +210,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent Utils.CopyText(pdfUrl.url.pathname), icon: "expand-arrows-alt" }); funcs.push({ description: "Toggle Fit Width " + (this.Document._fitWidth ? "Off" : "On"), event: () => this.Document._fitWidth = !this.Document._fitWidth, icon: "expand-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Pdf Funcs...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } @computed get contentScaling() { return this.props.ContentScaling(); } diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 11b24b059..125690dc7 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -120,7 +120,7 @@ export class ScreenshotBox extends ViewBoxBaseComponent { const funcs: ContextMenuProps[] = []; funcs.push({ description: "Edit Thumb Change Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Thumb Change ...", this.props.Document, "onThumbChange", obj.x, obj.y) }); - ContextMenu.Instance.addItem({ description: "Slider Funcs...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } onChange = (values: readonly number[]) => runInAction(() => { this.dataDoc[this.minThumbKey] = values[0]; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 588068334..613929bca 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -209,7 +209,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent Date: Fri, 24 Apr 2020 00:06:48 -0400 Subject: moved iconify code into Doc from DocumentView. fixed up starburst a bit. --- .../apis/google_docs/GooglePhotosClientUtils.ts | 21 +++--- src/client/util/RichTextSchema.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 16 +--- src/client/views/TemplateMenu.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 15 ++-- .../CollectionFreeFormLayoutEngines.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 31 +++++--- .../collections/collectionFreeForm/MarqueeView.tsx | 24 ++++-- src/client/views/nodes/DocumentView.tsx | 85 ++++++---------------- src/client/views/nodes/FormattedTextBox.tsx | 25 +++---- src/client/views/pdf/PDFViewer.tsx | 43 ++++++----- src/new_fields/Doc.ts | 85 ++++++++++++++++++++-- src/new_fields/RichTextUtils.ts | 32 ++++---- 13 files changed, 208 insertions(+), 177 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts index 7c4137f59..8c0149a89 100644 --- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts +++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts @@ -1,19 +1,18 @@ -import { Utils } from "../../../Utils"; -import { ImageField } from "../../../new_fields/URLField"; -import { Cast, StrCast } from "../../../new_fields/Types"; -import { Doc, Opt, DocListCastAsync } from "../../../new_fields/Doc"; +import { AssertionError } from "assert"; +import { EditorState } from "prosemirror-state"; +import { Doc, DocListCastAsync, Opt } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; -import Photos = require('googlephotos'); import { RichTextField } from "../../../new_fields/RichTextField"; import { RichTextUtils } from "../../../new_fields/RichTextUtils"; -import { EditorState } from "prosemirror-state"; -import { FormattedTextBox } from "../../views/nodes/FormattedTextBox"; +import { Cast, StrCast } from "../../../new_fields/Types"; +import { ImageField } from "../../../new_fields/URLField"; +import { MediaItem, NewMediaItemResult } from "../../../server/apis/google/SharedTypes"; +import { Utils } from "../../../Utils"; import { Docs, DocumentOptions } from "../../documents/Documents"; -import { NewMediaItemResult, MediaItem } from "../../../server/apis/google/SharedTypes"; -import { AssertionError } from "assert"; -import { DocumentView } from "../../views/nodes/DocumentView"; import { Networking } from "../../Network"; +import { FormattedTextBox } from "../../views/nodes/FormattedTextBox"; import GoogleAuthenticationManager from "../GoogleAuthenticationManager"; +import Photos = require('googlephotos'); export namespace GooglePhotos { @@ -340,7 +339,7 @@ export namespace GooglePhotos { const url = data.url.href; const target = Doc.MakeAlias(source); const description = parseDescription(target, descriptionKey); - await DocumentView.makeCustomViewClicked(target, Docs.Create.FreeformDocument); + await Doc.makeCustomViewClicked(target, Docs.Create.FreeformDocument); media.push({ url, description }); } if (media.length) { diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index d23962d5c..b88a7b017 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -780,7 +780,7 @@ export class DashDocView { if (dashDocBase instanceof Doc) { const aliasedDoc = Doc.MakeAlias(dashDocBase, docid + alias); aliasedDoc.layoutKey = "layout"; - node.attrs.fieldKey && DocumentView.makeCustomViewClicked(aliasedDoc, Docs.Create.StackingDocument, node.attrs.fieldKey, undefined); + node.attrs.fieldKey && Doc.makeCustomViewClicked(aliasedDoc, Docs.Create.StackingDocument, node.attrs.fieldKey, undefined); self.doRender(aliasedDoc, removeDoc, node, view, getPos); } }); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index e4ceb75bd..312acd5b2 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -193,7 +193,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> const selectedDocs = SelectionManager.SelectedDocuments(); if (selectedDocs.length) { //CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0], selectedDocs[0].props.LibraryPath); - CollectionDockingView.AddRightSplit(selectedDocs[0].props.Document, selectedDocs[0].props.LibraryPath); + CollectionDockingView.AddRightSplit(Doc.MakeAlias(selectedDocs[0].props.Document), selectedDocs[0].props.LibraryPath); } } SelectionManager.DeselectAll(); @@ -202,19 +202,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @action onIconifyClick = (e: PointerEvent): void => { if (e.button === 0) { - const selectedDocs = SelectionManager.SelectedDocuments().map(sd => sd); - selectedDocs.map(dv => { - const layoutKey = Cast(dv.props.Document.layoutKey, "string", null); - const collapse = layoutKey !== "layout_icon"; - if (collapse) { - dv.switchViews(collapse, "icon"); - if (layoutKey && layoutKey !== "layout") dv.props.Document.deiconifyLayout = layoutKey.replace("layout_", ""); - } else { - const deiconifyLayout = Cast(dv.props.Document.deiconifyLayout, "string", null); - dv.switchViews(deiconifyLayout ? true : false, deiconifyLayout); - dv.props.Document.deiconifyLayout = undefined; - } - }); + SelectionManager.SelectedDocuments().forEach(dv => dv?.iconify()); } SelectionManager.DeselectAll(); } diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index e3c749a4d..4c84a22ad 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -169,7 +169,7 @@ Scripting.addGlobal(function switchView(doc: Doc, template: Doc | undefined) { template = Cast(template.dragFactory, Doc, null); } const templateTitle = StrCast(template?.title); - return templateTitle && DocumentView.makeCustomViewClicked(doc, Docs.Create.FreeformDocument, templateTitle, template); + return templateTitle && Doc.makeCustomViewClicked(doc, Docs.Create.FreeformDocument, templateTitle, template); }); Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, selDoc: Doc) { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index a052d045c..ca2004b79 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -3,13 +3,14 @@ import { faAngleRight, faArrowsAltH, faBell, faCamera, faCaretDown, faCaretRight import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, runInAction, untracked } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, Field, HeightSym, WidthSym, DataSym, Opt } from '../../../new_fields/Doc'; +import { DataSym, Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; +import { RichTextField } from '../../../new_fields/RichTextField'; import { Document, listSpec } from '../../../new_fields/Schema'; import { ComputedField, ScriptField } from '../../../new_fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../new_fields/Types'; -import { emptyFunction, emptyPath, returnFalse, Utils, returnOne, returnZero, returnTransparent, returnTrue, simulateMouseClick } from '../../../Utils'; +import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from "../../documents/DocumentTypes"; import { DocumentManager } from '../../util/DocumentManager'; @@ -24,16 +25,14 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from "../EditableView"; import { MainView } from '../MainView'; import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView'; +import { DocumentView } from '../nodes/DocumentView'; import { ImageBox } from '../nodes/ImageBox'; import { KeyValueBox } from '../nodes/KeyValueBox'; -import { ScriptBox } from '../ScriptBox'; import { Templates } from '../Templates'; -import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView"; +import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; +import { CollectionViewType } from './CollectionView'; import React = require("react"); -import { CollectionViewType, CollectionView } from './CollectionView'; -import { RichTextField } from '../../../new_fields/RichTextField'; -import { DocumentView } from '../nodes/DocumentView'; export interface TreeViewProps { @@ -768,7 +767,7 @@ export class CollectionTreeView extends CollectionSubView UndoManager.RunInBatch(() => DocumentView.makeCustomViewClicked(this.props.Document, undefined, "onCheckedClick"), "edit onCheckedClick"), icon: "edit" + description: "Edit onChecked Script", event: () => UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onCheckedClick"), "edit onCheckedClick"), icon: "edit" }); !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 1ec0542a3..57f62347a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -113,8 +113,8 @@ export function computerStarburstLayout( const deg = i / childDocs.length * Math.PI * 2; docMap.set(doc, { type: "doc", - x: Math.sin(deg) * burstDim[0] / 3 - NumCast(pivotDoc.starburstX), - y: Math.cos(deg) * burstDim[1] / 3 - NumCast(pivotDoc.starburstY), + x: Math.cos(deg) * (burstDim[0] / 3) - doc[WidthSym]() / 2, + y: Math.sin(deg) * (burstDim[1] / 3) - doc[HeightSym]() / 2, width: doc[WidthSym](), height: doc[HeightSym](), payload: undefined diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index e8738b292..63199ccbb 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -885,13 +885,20 @@ export class CollectionFreeFormView extends CollectionSubView { + addDocTab = action((doc: Doc, where: string) => { + if (where === "inParent") { + const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); + doc.x = pt[0]; + doc.y = pt[1]; + this.props.addDocument(doc); + return true; + } if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { this.dataDoc[this.props.fieldKey] = new List([doc]); return true; } return this.props.addDocTab(doc, where); - } + }) getCalculatedPositions(params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): PoolData { const result = this.Document.arrangeScript?.script.run(params, console.log); if (result?.success) { @@ -1031,15 +1038,15 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.layoutDoc._layoutEngine === undefined) { - Doc.makeStarburst(this.layoutDoc); - } else { - this.layoutDoc._layoutEngine = undefined; - this.layoutDoc.overflow = "hidden"; - this.layoutDoc._fitToBox = undefined; - } - }); + promoteCollection = undoBatch(action(() => { + this.childDocs.forEach(doc => { + const scr = this.getTransform().inverse().transformPoint(NumCast(doc.x), NumCast(doc.y)); + doc.x = scr?.[0]; + doc.y = scr?.[1]; + this.props.addDocTab(doc, "inParent") && this.props.removeDocument(doc); + }) + this.props.ContainingCollectionView?.removeDocument(this.props.Document); + })); layoutDocsInGrid = () => { UndoManager.RunInBatch(() => { const docs = this.childLayoutPairs; @@ -1073,7 +1080,7 @@ export class CollectionFreeFormView extends CollectionSubView this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); optionItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); - optionItems.push({ description: "Arrange Starburst", event: this.layoutStarburst, icon: "table" }); + this.props.ContainingCollectionView && optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" }); optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }); // layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" }); optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = (this.props.Document.jitterRotation ? 0 : 10)), icon: "paint-brush" }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 2518ac629..d8e73a820 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -335,21 +335,33 @@ export class MarqueeView extends React.Component { - const bounds = this.Bounds; const selected = this.marqueeSelect(false); - selected.map(d => { + SelectionManager.DeselectAll(); + + let w = 0, h = 0; + selected.forEach((d, i) => { + Doc.iconify(d); + w = Math.max(d[WidthSym](), w); + h = Math.max(d[HeightSym](), h); + }); + selected.forEach((d, i) => { this.props.removeDocument(d); - d.x = NumCast(d.x) - bounds.left - bounds.width / 2; - d.y = NumCast(d.y) - bounds.top - bounds.height / 2; + d.x = Math.cos(Math.PI * 2 * i / selected.length) * 10 - w / 2; + d.y = Math.sin(Math.PI * 2 * i / selected.length) * 10 - h / 2; d.displayTimecode = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection - return d; }); const newCollection = this.getCollection(selected, false); + newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - 55; + newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - 55; + newCollection._width = newCollection._height = 110; + //newCollection.borderRounding = "40px"; + newCollection.jitterRotation = 10; + newCollection._backgroundColor = "yellow"; this.props.addDocument(newCollection); this.props.selectDocuments([newCollection], []); MarqueeOptionsMenu.Instance.fadeOut(true); this.hideMarquee(); - Doc.makeStarburst(newCollection); + Doc.pileup(newCollection); } @action diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6c8e44e95..cc8773ed5 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -307,7 +307,7 @@ export class DocumentView extends DocComponent(Docu UndoManager.RunInBatch(func, "on click"); } else func(); } else if (this.Document["onClick-rawScript"] && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) {// bcz: hack? don't edit a script if you're clicking on a scripting box itself - UndoManager.RunInBatch(() => DocumentView.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"); + UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"); //ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY), "on button click"); } else if (this.Document.isLinkButton) { DocListCast(this.props.Document.links).length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey); @@ -403,6 +403,19 @@ export class DocumentView extends DocComponent(Docu } } + public iconify() { + const layoutKey = Cast(this.props.Document.layoutKey, "string", null); + const collapse = layoutKey !== "layout_icon"; + if (collapse) { + this.switchViews(collapse, "icon"); + if (layoutKey && layoutKey !== "layout") this.props.Document.deiconifyLayout = layoutKey.replace("layout_", ""); + } else { + const deiconifyLayout = Cast(this.props.Document.deiconifyLayout, "string", null); + this.switchViews(deiconifyLayout ? true : false, deiconifyLayout); + this.props.Document.deiconifyLayout = undefined; + } + } + @action handle2PointersMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent) => { const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true); @@ -547,56 +560,6 @@ export class DocumentView extends DocComponent(Docu @undoBatch deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument?.(this.props.Document); } - // applies a custom template to a document. the template is identified by it's short name (e.g, slideView not layout_slideView) - static makeCustomViewClicked = (doc: Doc, creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) => { - const batch = UndoManager.StartBatch("makeCustomViewClicked"); - runInAction(() => { - doc.layoutKey = "layout_" + templateSignature; - if (doc[doc.layoutKey] === undefined) { - DocumentView.createCustomView(doc, creator, templateSignature, docLayoutTemplate); - } - }); - batch.end(); - } - static findTemplate(templateName: string, type: string, signature: string) { - let docLayoutTemplate: Opt; - const iconViews = DocListCast(Cast(Doc.UserDoc()["template-icons"], Doc, null)?.data); - const templBtns = DocListCast(Cast(Doc.UserDoc()["template-buttons"], Doc, null)?.data); - const noteTypes = DocListCast(Cast(Doc.UserDoc()["template-notes"], 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) === templateName + "_" + type && (docLayoutTemplate = tempDoc)); - !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName && (docLayoutTemplate = tempDoc)); - return docLayoutTemplate; - } - static createCustomView = (doc: Doc, creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) => { - const templateName = templateSignature.replace(/\(.*\)/, ""); - docLayoutTemplate = docLayoutTemplate || DocumentView.findTemplate(templateName, StrCast(doc.type), templateSignature); - - const customName = "layout_" + templateSignature; - const _width = NumCast(doc._width); - const _height = NumCast(doc._height); - const options = { title: "data", backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: - _height / 2, _showSidebar: false }; - - let fieldTemplate: Opt; - if (doc.data instanceof RichTextField || typeof (doc.data) === "string") { - fieldTemplate = Docs.Create.TextDocument("", options); - } else if (doc.data instanceof PdfField) { - fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options); - } else if (doc.data instanceof VideoField) { - fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options); - } else if (doc.data instanceof AudioField) { - fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options); - } else if (doc.data instanceof ImageField) { - fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options); - } - const docTemplate = docLayoutTemplate || creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) }); - - fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate); - docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined); - } @undoBatch toggleLinkButtonBehavior = (): void => { @@ -667,15 +630,6 @@ export class DocumentView extends DocComponent(Docu this.Document.isLinkButton = true; } - @undoBatch - @action - setCustomView = (custom: boolean, layout: string): void => { - Doc.setNativeView(this.props.Document); - if (custom) { - DocumentView.makeCustomViewClicked(this.props.Document, Docs.Create.StackingDocument, layout, undefined); - } - } - @undoBatch @action toggleBackground = (temporary: boolean): void => { @@ -747,7 +701,7 @@ export class DocumentView extends DocComponent(Docu onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" }); onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" }); onClicks.push({ description: this.Document.isLinkButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" }); - onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocumentView.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" }); + onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" }); !existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); const funcs: ContextMenuProps[] = []; @@ -1114,7 +1068,14 @@ export class DocumentView extends DocComponent(Docu @computed get ignorePointerEvents() { return this.props.pointerEvents === false || (this.Document.isBackground && !this.isSelected() && !SelectionManager.GetIsDragging()) || (this.Document.type === DocumentType.INK && InkingControl.Instance.selectedTool !== InkTool.None); } - + @undoBatch + @action + setCustomView = (custom: boolean, layout: string): void => { + Doc.setNativeView(this.props.Document); + if (custom) { + Doc.makeCustomViewClicked(this.props.Document, Docs.Create.StackingDocument, layout, undefined); + } + } @observable _animate = 0; switchViews = action((custom: boolean, view: string) => { SelectionManager.SetIsDragging(true); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 6ed2a1b9e..f71343176 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -13,22 +13,24 @@ import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from " import { ReplaceStep } from 'prosemirror-transform'; import { EditorView } from "prosemirror-view"; import { DateField } from '../../../new_fields/DateField'; -import { DataSym, Doc, DocListCastAsync, Field, HeightSym, Opt, WidthSym, DocListCast } from "../../../new_fields/Doc"; +import { DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; import { documentSchema } from '../../../new_fields/documentSchemas'; import { Id } from '../../../new_fields/FieldSymbols'; import { InkTool } from '../../../new_fields/InkField'; +import { PrefetchProxy } from '../../../new_fields/Proxy'; import { RichTextField } from "../../../new_fields/RichTextField"; import { RichTextUtils } from '../../../new_fields/RichTextUtils'; import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { Cast, NumCast, StrCast, BoolCast, DateCast } from "../../../new_fields/Types"; +import { Cast, DateCast, NumCast, StrCast } from "../../../new_fields/Types"; import { TraceMobx } from '../../../new_fields/util'; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, Utils, returnTrue, returnZero } from '../../../Utils'; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils } from '../../../Utils'; import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils'; import { DocServer } from "../../DocServer"; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { DictationManager } from '../../util/DictationManager'; import { DragManager } from "../../util/DragManager"; +import { makeTemplate } from '../../util/DropConverter'; import buildKeymap from "../../util/ProsemirrorExampleTransfer"; import RichTextMenu from '../../util/RichTextMenu'; import { RichTextRules } from "../../util/RichTextRules"; @@ -46,9 +48,6 @@ import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './FormattedTextBoxComment'; import React = require("react"); -import { PrefetchProxy } from '../../../new_fields/Proxy'; -import { makeTemplate } from '../../util/DropConverter'; -import { DocumentView } from './DocumentView'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -436,24 +435,24 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const noteTypesDoc = Cast(Doc.UserDoc()["template-notes"], Doc, null); DocListCast(noteTypesDoc?.data).forEach(note => { changeItems.push({ - description: StrCast(note.title), event: () => { + description: StrCast(note.title), event: undoBatch(() => { Doc.setNativeView(this.props.Document); - DocumentView.makeCustomViewClicked(this.rootDoc, Docs.Create.TreeDocument, StrCast(note.title), note); - }, icon: "eye" + Doc.makeCustomViewClicked(this.rootDoc, Docs.Create.TreeDocument, StrCast(note.title), note); + }), icon: "eye" }); }); - changeItems.push({ description: "FreeForm", event: () => DocumentView.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), icon: "eye" }); + changeItems.push({ description: "FreeForm", event: undoBatch(() => Doc.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), "change view"), icon: "eye" }); !change && cm.addItem({ description: "Change Perspective...", subitems: changeItems, icon: "external-link-alt" }); const open = cm.findByDescription("Open New Perspective..."); const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; openItems.push({ - description: "FreeForm", event: () => { + description: "FreeForm", event: undoBatch(() => { const alias = Doc.MakeAlias(this.rootDoc); - DocumentView.makeCustomViewClicked(alias, Docs.Create.FreeformDocument, "freeform"); + Doc.makeCustomViewClicked(alias, Docs.Create.FreeformDocument, "freeform"); this.props.addDocTab(alias, "onRight"); - }, icon: "eye" + }), icon: "eye" }); !open && cm.addItem({ description: "Open New Perspective...", subitems: openItems, icon: "external-link-alt" }); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 46b60b554..acaa4363e 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -1,37 +1,36 @@ -import { action, computed, IReactionDisposer, observable, reaction, trace, runInAction } from "mobx"; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as Pdfjs from "pdfjs-dist"; import "pdfjs-dist/web/pdf_viewer.css"; +import * as rp from "request-promise"; import { Dictionary } from "typescript-collections"; -import { Doc, DocListCast, FieldResult, WidthSym, Opt, HeightSym } from "../../../new_fields/Doc"; -import { Id, Copy } from "../../../new_fields/FieldSymbols"; +import { Doc, DocListCast, FieldResult, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; +import { documentSchema } from "../../../new_fields/documentSchemas"; +import { Id } from "../../../new_fields/FieldSymbols"; +import { InkTool } from "../../../new_fields/InkField"; import { List } from "../../../new_fields/List"; -import { makeInterface, createSchema } from "../../../new_fields/Schema"; -import { ScriptField, ComputedField } from "../../../new_fields/ScriptField"; -import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { smoothScroll, Utils, emptyFunction, returnOne, intersectRect, addStyleSheet, addStyleSheetRule, clearStyleSheetRules, returnZero, emptyPath } from "../../../Utils"; +import { createSchema, makeInterface } from "../../../new_fields/Schema"; +import { ScriptField } from "../../../new_fields/ScriptField"; +import { Cast, NumCast } from "../../../new_fields/Types"; +import { PdfField } from "../../../new_fields/URLField"; +import { TraceMobx } from "../../../new_fields/util"; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, emptyPath, intersectRect, returnZero, smoothScroll, Utils } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; +import { DocumentType } from "../../documents/DocumentTypes"; import { DragManager } from "../../util/DragManager"; import { CompiledScript, CompileScript } from "../../util/Scripting"; -import { Transform } from "../../util/Transform"; -import PDFMenu from "./PDFMenu"; -import "./PDFViewer.scss"; -import React = require("react"); -import * as rp from "request-promise"; -import { CollectionView } from "../collections/CollectionView"; -import Annotation from "./Annotation"; -import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { SelectionManager } from "../../util/SelectionManager"; +import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; +import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; +import { CollectionView } from "../collections/CollectionView"; import { ViewBoxAnnotatableComponent } from "../DocComponent"; -import { DocumentType } from "../../documents/DocumentTypes"; -import { documentSchema } from "../../../new_fields/documentSchemas"; import { DocumentDecorations } from "../DocumentDecorations"; import { InkingControl } from "../InkingControl"; -import { InkTool } from "../../../new_fields/InkField"; -import { TraceMobx } from "../../../new_fields/util"; -import { PdfField } from "../../../new_fields/URLField"; -import { DocumentView } from "../nodes/DocumentView"; +import Annotation from "./Annotation"; +import PDFMenu from "./PDFMenu"; +import "./PDFViewer.scss"; +import React = require("react"); const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer"); const pdfjsLib = require("pdfjs-dist"); @@ -574,7 +573,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent([clipDoc]); clipDoc.rootDocument = targetDoc; - DocumentView.makeCustomViewClicked(targetDoc, Docs.Create.StackingDocument, "slideView", undefined); + Doc.makeCustomViewClicked(targetDoc, Docs.Create.StackingDocument, "slideView", undefined); targetDoc.layoutKey = "layout"; // const targetDoc = Docs.Create.TextDocument("", { _width: 200, _height: 200, title: "Note linked to " + this.props.Document.title }); // Doc.GetProto(targetDoc).snipped = this.dataDoc[this.props.fieldKey][Copy](); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 1373431b8..cc929c040 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -17,7 +17,8 @@ import { listSpec } from "./Schema"; import { ComputedField, ScriptField } from "./ScriptField"; import { Cast, FieldValue, NumCast, StrCast, ToConstructor, ScriptCast } from "./Types"; import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util"; -import { Docs } from "../client/documents/Documents"; +import { Docs, DocumentOptions } from "../client/documents/Documents"; +import { PdfField, VideoField, AudioField, ImageField } from "./URLField"; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { @@ -913,18 +914,86 @@ export namespace Doc { return false; } - export function makeStarburst(newCollection: Doc) { - newCollection._layoutEngine = "starburst"; - newCollection._fitToBox = true; + // applies a custom template to a document. the template is identified by it's short name (e.g, slideView not layout_slideView) + export function makeCustomViewClicked(doc: Doc, creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) { + const batch = UndoManager.StartBatch("makeCustomViewClicked"); + runInAction(() => { + doc.layoutKey = "layout_" + templateSignature; + if (doc[doc.layoutKey] === undefined) { + createCustomView(doc, creator, templateSignature, docLayoutTemplate); + } + }); + batch.end(); + } + export function findTemplate(templateName: string, type: string, signature: string) { + let docLayoutTemplate: Opt; + const iconViews = DocListCast(Cast(Doc.UserDoc()["template-icons"], Doc, null)?.data); + const templBtns = DocListCast(Cast(Doc.UserDoc()["template-buttons"], Doc, null)?.data); + const noteTypes = DocListCast(Cast(Doc.UserDoc()["template-notes"], 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) === templateName + "_" + type && (docLayoutTemplate = tempDoc)); + !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName && (docLayoutTemplate = tempDoc)); + return docLayoutTemplate; + } + export function createCustomView(doc: Doc, creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) { + const templateName = templateSignature.replace(/\(.*\)/, ""); + docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc.type), templateSignature); + + const customName = "layout_" + templateSignature; + const _width = NumCast(doc._width); + const _height = NumCast(doc._height); + const options = { title: "data", backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: - _height / 2, _showSidebar: false }; + + let fieldTemplate: Opt; + if (doc.data instanceof RichTextField || typeof (doc.data) === "string") { + fieldTemplate = Docs.Create.TextDocument("", options); + } else if (doc.data instanceof PdfField) { + fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options); + } else if (doc.data instanceof VideoField) { + fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options); + } else if (doc.data instanceof AudioField) { + fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options); + } else if (doc.data instanceof ImageField) { + fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options); + } + const docTemplate = docLayoutTemplate || creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) }); + + fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate); + docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined); + } + export function makeCustomView(doc: Doc, custom: boolean, layout: string) { + Doc.setNativeView(doc); + if (custom) { + makeCustomViewClicked(doc, Docs.Create.StackingDocument, layout, undefined); + } + } + export function iconify(doc: Doc) { + const layoutKey = Cast(doc.layoutKey, "string", null); + Doc.makeCustomViewClicked(doc, Docs.Create.StackingDocument, "icon", undefined); + if (layoutKey && layoutKey !== "layout") doc.deiconifyLayout = layoutKey.replace("layout_", ""); + } + + export function pileup(newCollection: Doc) { + newCollection._layoutEngine = "pass"; newCollection.overflow = "visible"; const script = "if (self._layoutEngine === 'starburst') {" + - " self._layoutEngine = 'pass';" + " self.overflow = undefined;" + - " self.fitToContentScaling=undefined;" + + " self.x = self.x + self._width/2 - 55; " + + " self.y = self.y + self._height/2 - 55; " + + " self._width = self._height = 110;" + + " self._layoutEngine = 'pass';" + " } else {" + - " self._layoutEngine = 'starburst';" + " self.overflow = 'visible';" + - " self.fitToContentScaling=10;" + + " !self.starburstRadius && (self.starburstRadius = 500);" + + " if (self._layoutEngine === 'pass') { " + + " self.x = self.x + self._width/2 - 12.5; " + + " self.y = self.y + self._height/2 - 12.5; " + + " }; " + + " self._width = self._height = 25;" + + " self._layoutEngine = 'starburst';" + " };"; newCollection.onClick = ScriptField.MakeScript(script, { self: Doc.name }); } diff --git a/src/new_fields/RichTextUtils.ts b/src/new_fields/RichTextUtils.ts index c211b3d3c..635fd053d 100644 --- a/src/new_fields/RichTextUtils.ts +++ b/src/new_fields/RichTextUtils.ts @@ -1,23 +1,21 @@ -import { EditorState, Transaction, TextSelection } from "prosemirror-state"; -import { Node, Fragment, Mark } from "prosemirror-model"; -import { RichTextField } from "./RichTextField"; +import { AssertionError } from "assert"; import { docs_v1 } from "googleapis"; -import { GoogleApiClientUtils } from "../client/apis/google_docs/GoogleApiClientUtils"; -import { FormattedTextBox } from "../client/views/nodes/FormattedTextBox"; -import { Opt, Doc } from "./Doc"; -import Color = require('color'); +import { Fragment, Mark, Node } from "prosemirror-model"; import { sinkListItem } from "prosemirror-schema-list"; -import { Utils } from "../Utils"; -import { Docs } from "../client/documents/Documents"; -import { schema } from "../client/util/RichTextSchema"; +import { EditorState, TextSelection, Transaction } from "prosemirror-state"; +import { GoogleApiClientUtils } from "../client/apis/google_docs/GoogleApiClientUtils"; import { GooglePhotos } from "../client/apis/google_docs/GooglePhotosClientUtils"; import { DocServer } from "../client/DocServer"; -import { Cast, StrCast } from "./Types"; -import { Id } from "./FieldSymbols"; -import { DocumentView } from "../client/views/nodes/DocumentView"; -import { AssertionError } from "assert"; +import { Docs } from "../client/documents/Documents"; import { Networking } from "../client/Network"; -import { extname } from "path"; +import { schema } from "../client/util/RichTextSchema"; +import { FormattedTextBox } from "../client/views/nodes/FormattedTextBox"; +import { Utils } from "../Utils"; +import { Doc, Opt } from "./Doc"; +import { Id } from "./FieldSymbols"; +import { RichTextField } from "./RichTextField"; +import { Cast, StrCast } from "./Types"; +import Color = require('color'); export namespace RichTextUtils { @@ -274,7 +272,7 @@ export namespace RichTextUtils { const backingDocId = StrCast(textNote[guid]); if (!backingDocId) { const backingDoc = Docs.Create.ImageDocument(agnostic, { _width: 300, _height: 300 }); - DocumentView.makeCustomViewClicked(backingDoc, Docs.Create.FreeformDocument); + Doc.makeCustomViewClicked(backingDoc, Docs.Create.FreeformDocument); docid = backingDoc[Id]; textNote[guid] = docid; } else { @@ -403,7 +401,7 @@ export namespace RichTextUtils { let exported = (await Cast(linkDoc.anchor2, Doc))!; if (!exported.customLayout) { exported = Doc.MakeAlias(exported); - DocumentView.makeCustomViewClicked(exported, Docs.Create.FreeformDocument); + Doc.makeCustomViewClicked(exported, Docs.Create.FreeformDocument); linkDoc.anchor2 = exported; } url = Utils.shareUrl(exported[Id]); -- cgit v1.2.3-70-g09d2 From f1ac48c19b4683668b0df91bd4ad68690a069029 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 25 Apr 2020 21:43:21 -0400 Subject: added a targetDropAction field to specify the drop action from the target's side --- src/client/util/DragManager.ts | 15 ++++++++++----- src/client/views/collections/CollectionCarouselView.tsx | 2 +- src/client/views/collections/CollectionLinearView.tsx | 2 +- .../views/collections/CollectionSchemaMovableTableHOC.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 9 ++------- src/client/views/collections/CollectionTreeView.tsx | 4 ++-- src/client/views/collections/CollectionViewChromes.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 4 ++-- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/LabelBox.tsx | 2 +- src/new_fields/documentSchemas.ts | 3 ++- 12 files changed, 26 insertions(+), 25 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 6a55f4a00..577366cd4 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,5 +1,5 @@ import { Doc, Field, DocListCast } from "../../new_fields/Doc"; -import { Cast, ScriptCast } from "../../new_fields/Types"; +import { Cast, ScriptCast, StrCast } from "../../new_fields/Types"; import { emptyFunction } from "../../Utils"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import * as globalCssVariables from "../views/globalCssVariables.scss"; @@ -180,7 +180,7 @@ export namespace DragManager { export function MakeDropTarget( element: HTMLElement, dropFunc: (e: Event, de: DropEvent) => void, - preDropFunc?: (e: Event, de: DropEvent) => void + doc?:Doc ): DragDropDisposer { if ("canDrop" in element.dataset) { throw new Error( @@ -189,12 +189,17 @@ export namespace DragManager { } element.dataset.canDrop = "true"; const handler = (e: Event) => dropFunc(e, (e as CustomEvent).detail); - const preDropHandler = (e: Event) => preDropFunc?.(e, (e as CustomEvent).detail); + const preDropHandler = (e:Event) => { + const de = (e as CustomEvent).detail; + if (de.complete.docDragData && doc?.targetDropAction) { + de.complete.docDragData!.dropAction = StrCast(doc.targetDropAction) as dropActionType; + } + } element.addEventListener("dashOnDrop", handler); - preDropFunc && element.addEventListener("dashPreDrop", preDropHandler); + doc && element.addEventListener("dashPreDrop", preDropHandler); return () => { element.removeEventListener("dashOnDrop", handler); - preDropFunc && element.removeEventListener("dashPreDrop", preDropHandler); + doc && element.removeEventListener("dashPreDrop", preDropHandler); delete element.dataset.canDrop; }; } diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 9e7248db2..2453acddf 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -27,7 +27,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view this._dropDisposer?.(); if (ele) { - this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this)); + this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); } } diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx index cb0206260..344dca23a 100644 --- a/src/client/views/collections/CollectionLinearView.tsx +++ b/src/client/views/collections/CollectionLinearView.tsx @@ -64,7 +64,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view this._dropDisposer && this._dropDisposer(); if (ele) { - this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this)); + this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); } } diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx index 670d6dbb2..972714e34 100644 --- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx +++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx @@ -54,7 +54,7 @@ export class MovableColumn extends React.Component { } createColDropTarget = (ele: HTMLDivElement) => { - this._colDropDisposer && this._colDropDisposer(); + this._colDropDisposer?.(); if (ele) { this._colDropDisposer = DragManager.MakeDropTarget(ele, this.colDrop.bind(this)); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 60cc1bd49..49abc6ee6 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -11,7 +11,7 @@ import { Utils } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { DocumentType } from "../../documents/DocumentTypes"; import { Docs, DocumentOptions } from "../../documents/Documents"; -import { DragManager } from "../../util/DragManager"; +import { DragManager, dropActionType } from "../../util/DragManager"; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { DocComponent } from "../DocComponent"; import { FieldViewProps } from "../nodes/FieldView"; @@ -64,7 +64,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: this.multiTouchDisposer?.(); if (ele) { this._mainCont = ele; - this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.onInternalPreDrop.bind(this)); + this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this)); this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this)); } @@ -208,11 +208,6 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: protected onGesture(e: Event, ge: GestureUtils.GestureEvent) { } - protected onInternalPreDrop(e: Event, de: DragManager.DropEvent): boolean { - // de.complete.docDragData!.dropAction = "alias"; bcz: for example, you can convert all drops to aliases here - return true; - } - @undoBatch @action protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index ca2004b79..8c5a4538e 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -143,7 +143,7 @@ class TreeView extends React.Component { protected createTreeDropTarget = (ele: HTMLDivElement) => { this._treedropDisposer && this._treedropDisposer(); - ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this))); + ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this)), this.props.document); } onPointerEnter = (e: React.PointerEvent): void => { @@ -663,7 +663,7 @@ export class CollectionTreeView extends CollectionSubView { this.treedropDisposer?.(); if (this._mainEle = ele) { - this.treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this)); + this.treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.props.Document); } } diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 7315d2c4e..d26e3a38b 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -215,9 +215,9 @@ export class CollectionViewBaseChrome extends React.Component { - this.dropDisposer && this.dropDisposer(); + this.dropDisposer?.(); if (ele) { - this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)); + this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.document); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7ae77fc65..2aee49ad3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -191,7 +191,7 @@ export class DocumentView extends DocComponent(Docu @action componentDidMount() { - this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this))); + this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document)); this._mainCont.current && (this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this))); this._mainCont.current && (this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this))); // this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this))); @@ -208,7 +208,7 @@ export class DocumentView extends DocComponent(Docu this.multiTouchDisposer?.(); this.holdDisposer?.(); if (this._mainCont.current) { - this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this)); + this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document); this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this)); this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)); this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this)); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index d7cfbae9f..815b8b3ae 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -253,7 +253,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp protected createDropTarget = (ele: HTMLDivElement) => { this.ProseRef = ele; this.dropDisposer?.(); - ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this))); + ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document)); } @undoBatch diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 14b367868..08917d281 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -76,7 +76,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { this._dropDisposer && this._dropDisposer(); - ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this))); + ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document)); } @undoBatch diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 5c2fc3ffe..a41e4fac4 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -32,7 +32,7 @@ export class LabelBox extends ViewBoxBaseComponent { this.dropDisposer?.(); if (ele) { - this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)); + this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document); } } diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index 61b185e5c..f24ad42b2 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -8,7 +8,8 @@ export const documentSchema = createSchema({ layout: "string", // this is the native layout string for the document. templates can be added using other fields and setting layoutKey below layoutKey: "string", // holds the field key for the field that actually holds the current lyoat title: "string", // document title (can be on either data document or layout) - dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias" or "copy") + dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias", "copy", "move") + targetDropAction: "string", // allows the target of a drop event to specify the dropAction ("alias", "copy", "move") childDropAction: "string", // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "alias" or "copy") _autoHeight: "boolean", // whether the height of the document should be computed automatically based on its contents _nativeWidth: "number", // native width of document which determines how much document contents are scaled when the document's width is set -- cgit v1.2.3-70-g09d2 From e6549d43be83b50d364c4a3ab1e8e7381ce2fd59 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 26 Apr 2020 01:56:41 -0400 Subject: fixed title layout for text. fixed documentBox for nested collections. fixed tree view for text boxes. changed labelbox formatting. --- src/client/util/DragManager.ts | 8 ++++---- src/client/views/collections/CollectionTreeView.tsx | 13 +++++++++---- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 ++- src/client/views/nodes/ColorBox.scss | 1 + src/client/views/nodes/DocumentBox.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 7 ++----- src/client/views/nodes/FormattedTextBox.scss | 1 - src/client/views/nodes/FormattedTextBox.tsx | 4 ++-- src/client/views/nodes/LabelBox.scss | 2 -- src/client/views/nodes/LabelBox.tsx | 8 +++++++- src/server/authentication/models/current_user_utils.ts | 4 ++-- 11 files changed, 31 insertions(+), 24 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 577366cd4..35694a6bd 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -180,7 +180,7 @@ export namespace DragManager { export function MakeDropTarget( element: HTMLElement, dropFunc: (e: Event, de: DropEvent) => void, - doc?:Doc + doc?: Doc ): DragDropDisposer { if ("canDrop" in element.dataset) { throw new Error( @@ -189,12 +189,12 @@ export namespace DragManager { } element.dataset.canDrop = "true"; const handler = (e: Event) => dropFunc(e, (e as CustomEvent).detail); - const preDropHandler = (e:Event) => { + const preDropHandler = (e: Event) => { const de = (e as CustomEvent).detail; if (de.complete.docDragData && doc?.targetDropAction) { - de.complete.docDragData!.dropAction = StrCast(doc.targetDropAction) as dropActionType; + de.complete.docDragData.dropAction = StrCast(doc.targetDropAction) as dropActionType; } - } + }; element.addEventListener("dashOnDrop", handler); doc && element.addEventListener("dashPreDrop", preDropHandler); return () => { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 8c5a4538e..ddd7474bd 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -261,7 +261,7 @@ class TreeView extends React.Component { docHeight = () => { const layoutDoc = Doc.Layout(this.props.document); const bounds = this.boundsOfCollectionDocument; - return Math.min(this.MAX_EMBED_HEIGHT, (() => { + return Math.max(70, Math.min(this.MAX_EMBED_HEIGHT, (() => { const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]()); if (aspect) return this.docWidth() * aspect; if (bounds) return this.docWidth() * (bounds.b - bounds.y) / (bounds.r - bounds.x); @@ -269,7 +269,7 @@ class TreeView extends React.Component { Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth, NumCast(this.props.containingCollection._height)))) : NumCast(layoutDoc._height) ? NumCast(layoutDoc._height) : 50; - })()); + })())); } @computed get expandedField() { @@ -321,6 +321,9 @@ class TreeView extends React.Component { return rows; } + rtfWidth = () => Math.min(Doc.Layout(this.props.document)?.[WidthSym](), this.props.panelWidth() - 20); + rtfHeight = () => this.rtfWidth() < Doc.Layout(this.props.document)?.[WidthSym]() ? Math.min(Doc.Layout(this.props.document)?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT; + @computed get renderContent() { const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined; if (expandKey !== undefined) { @@ -355,8 +358,10 @@ class TreeView extends React.Component { backgroundColor={this.props.backgroundColor} fitToBox={this.boundsOfCollectionDocument !== undefined} FreezeDimensions={true} - PanelWidth={this.docWidth} - PanelHeight={this.docHeight} + NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined} + NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined} + PanelWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : this.docWidth} + PanelHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : this.docHeight} getTransform={this.docTransform} CollectionDoc={this.props.containingCollection} CollectionView={undefined} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 852442fd4..28b461313 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1026,7 +1026,8 @@ export class CollectionFreeFormView extends CollectionSubView, bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica) diff --git a/src/client/views/nodes/ColorBox.scss b/src/client/views/nodes/ColorBox.scss index bf334c939..da3266dc1 100644 --- a/src/client/views/nodes/ColorBox.scss +++ b/src/client/views/nodes/ColorBox.scss @@ -3,6 +3,7 @@ height:100%; position: relative; pointer-events: none; + transform-origin: top left; .sketch-picker { margin:auto; diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx index 0111cadd5..0d18baaed 100644 --- a/src/client/views/nodes/DocumentBox.tsx +++ b/src/client/views/nodes/DocumentBox.tsx @@ -120,8 +120,8 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent(Docu layoutKey={this.finalLayoutKey} /> ); const titleView = (!showTitle ? (null) : -
    @@ -1086,10 +1086,7 @@ export class DocumentView extends DocComponent(Docu return !showTitle && !showCaption ? this.contents :
    -
    - {this.contents} -
    - {titleView} + {this.Document.type !== DocumentType.RTF ? <> {this.contents} {titleView} : <> {titleView} {this.contents} } {captionView}
    ; } diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index 7a05ec3a3..3bedb7127 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -24,7 +24,6 @@ overflow-y: auto; overflow-x: hidden; color: initial; - height: 100%; max-height: 100%; display: flex; flex-direction: row; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 815b8b3ae..425af8ccf 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -194,7 +194,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const tsel = this._editorView.state.selection.$from; tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 1000))); - const curText = state.doc.textBetween(0, state.doc.content.size, "\n\n"); + const curText = state.doc.textBetween(0, state.doc.content.size, " \n"); const curTemp = Cast(this.props.Document[this.props.fieldKey + "-textTemplate"], RichTextField); if (!this._applyingChange) { this._applyingChange = true; @@ -1211,7 +1211,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp return (
    {StrCast(this.rootDoc.text, StrCast(this.rootDoc.title))} diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index afde524b6..25775edef 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -167,7 +167,7 @@ export class CurrentUserUtils { doc["template-icon-view"] = new PrefetchProxy(iconView); } if (doc["template-icon-view-rtf"] === undefined) { - const iconRtfView = Docs.Create.LabelDocument({ title: "icon_" + DocumentType.RTF, textTransform: "unset", letterSpacing: "unset", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(self)") }); + const iconRtfView = Docs.Create.LabelDocument({ title: "icon_" + DocumentType.RTF, textTransform: "unset", letterSpacing: "unset", _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(self)") }); iconRtfView.isTemplateDoc = makeTemplate(iconRtfView, true, "icon_" + DocumentType.RTF); doc["template-icon-view-rtf"] = new PrefetchProxy(iconRtfView); } @@ -214,7 +214,7 @@ export class CurrentUserUtils { { 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 clickable button", label: "Btn", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, _xPadding:10, _yPadding: 10, title: "Button" })' }, { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory,true)`, dragFactory: doc.emptyPresentation as Doc }, { 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 scripting box", label: "Script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' }, -- cgit v1.2.3-70-g09d2 From 63985ba64dc4a3a94bac75a9120cd8a5ca791fec Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sun, 26 Apr 2020 11:28:03 -0700 Subject: buxton tweaks --- src/client/views/collections/CollectionTreeView.tsx | 7 ++++--- src/scraping/buxton/final/BuxtonImporter.ts | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index ddd7474bd..7f5dc98f1 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -727,7 +727,7 @@ export class CollectionTreeView extends CollectionSubView Date: Sun, 26 Apr 2020 21:22:51 -0400 Subject: fixed multi/col/row views to work with templates. fixed context menu subitems to appear on screen. fixed tree view display of text nodes. --- src/client/views/ContextMenu.scss | 47 +++++++++++++++++----- src/client/views/ContextMenuItem.tsx | 16 +++++--- .../views/collections/CollectionStackingView.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 20 +++++---- .../CollectionMulticolumnView.tsx | 31 +++++++++----- .../CollectionMultirowView.tsx | 31 +++++++++----- src/client/views/nodes/RadialMenu.scss | 13 ------ src/client/views/nodes/RadialMenu.tsx | 9 ++--- .../authentication/models/current_user_utils.ts | 28 ++++++++++++- 9 files changed, 133 insertions(+), 66 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 8f112de0c..30938688d 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -61,6 +61,42 @@ letter-spacing: 2px; text-transform: uppercase; padding-right: 30px; + + .icon-background { + pointer-events: all; + background-color: transparent; + width: 35px; + text-align: center; + font-size: 20px; + margin-left: 5px; + margin-top: 5px; + margin-bottom: 5px; + height: 20px; + } +} +.contextMenu-description { + // width: 11vw; //10vw + background: whitesmoke; + display: flex; //comment out to allow search icon to be inline with search text + justify-content: left; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + transition: all .1s; + border-style: none; + // padding: 10px 0px 10px 0px; + white-space: nowrap; + font-size: 13px; + color: grey; + letter-spacing: 2px; + text-transform: uppercase; + padding-right: 30px; + margin-top: 5px; + height: 20px; + margin-bottom: 5px; } .contextMenu-item:hover { @@ -121,15 +157,4 @@ padding-left: 10px; border: solid black 1px; border-radius: 5px; -} - -.icon-background { - pointer-events: all; - height:100%; - margin-top: 15px; - background-color: transparent; - width: 35px; - text-align: center; - font-size: 20px; - margin-left: 5px; } \ No newline at end of file diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index fef9e5f60..99840047f 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -51,7 +51,8 @@ export class ContextMenuItem extends React.Component { + _overPosY = 0; + onPointerEnter = (e: React.MouseEvent) => { if (this.currentTimeout) { clearTimeout(this.currentTimeout); this.currentTimeout = undefined; @@ -59,6 +60,7 @@ export class ContextMenuItem extends React.Component this.overItem = true), ContextMenuItem.timeout); } @@ -88,18 +90,22 @@ export class ContextMenuItem extends React.Component ); } else if ("subitems" in this.props) { + const where = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "flex-start" : this._overPosY > window.innerHeight * 2 / 3 ? "flex-end" : "center"; + const marginTop = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "20px" : this._overPosY > window.innerHeight * 2 / 3 ? "-20px" : ""; const submenu = !this.overItem ? (null) : -
    +
    {this._items.map(prop => )}
    ; return ( -
    +
    {this.props.icon ? ( - + ) : null} -
    +
    {this.props.description}
    diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 24a3119cc..799bc7f67 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -189,8 +189,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { active={this.props.active} whenActiveChanged={this.props.whenActiveChanged} addDocTab={this.addDocTab} - pinToPres={this.props.pinToPres}> - ; + pinToPres={this.props.pinToPres} + />; } getDocWidth(d?: Doc) { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 7f5dc98f1..218c5705d 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -348,7 +348,9 @@ class TreeView extends React.Component {
    ; } else { const layoutDoc = Doc.Layout(this.props.document); - return
    + const panelHeight = layoutDoc.type === DocumentType.RTF ? this.rtfHeight : this.docHeight; + const panelWidth = layoutDoc.type === DocumentType.RTF ? this.rtfWidth : this.docWidth; + return
    { FreezeDimensions={true} NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined} NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined} - PanelWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : this.docWidth} - PanelHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : this.docHeight} + PanelWidth={panelWidth} + PanelHeight={panelHeight} getTransform={this.docTransform} CollectionDoc={this.props.containingCollection} CollectionView={undefined} @@ -727,7 +729,7 @@ export class CollectionTreeView extends CollectionSubView Transform, width: () => number, height: () => number) { return ; } /** diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 1eb486c4f..af0cc3b5c 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -13,7 +13,7 @@ import { Transform } from '../../../util/Transform'; import HeightLabel from './MultirowHeightLabel'; import ResizeBar from './MultirowResizer'; import { undoBatch } from '../../../util/UndoManager'; -import { DragManager } from '../../../util/DragManager'; +import { DragManager, dropActionType } from '../../../util/DragManager'; import { List } from '../../../../new_fields/List'; type MultirowDocument = makeInterface<[typeof documentSchema]>; @@ -214,21 +214,32 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument) } getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) { return ; } /** diff --git a/src/client/views/nodes/RadialMenu.scss b/src/client/views/nodes/RadialMenu.scss index ce0c263ef..daa620d12 100644 --- a/src/client/views/nodes/RadialMenu.scss +++ b/src/client/views/nodes/RadialMenu.scss @@ -67,17 +67,4 @@ s margin-left: 5px; text-align: left; display: inline; //need this? -} - - - -.icon-background { - pointer-events: all; - height:100%; - margin-top: 15px; - background-color: transparent; - width: 35px; - text-align: center; - font-size: 20px; - margin-left: 5px; } \ No newline at end of file diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx index 0ffed78de..ddfdb67b4 100644 --- a/src/client/views/nodes/RadialMenu.tsx +++ b/src/client/views/nodes/RadialMenu.tsx @@ -1,12 +1,9 @@ import React = require("react"); +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { action, observable, computed, IReactionDisposer, reaction, runInAction } from "mobx"; -import { RadialMenuItem, RadialMenuProps } from "./RadialMenuItem"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import Measure from "react-measure"; -import "./RadialMenu.scss"; -import MobileInkOverlay from "../../../mobile/MobileInkOverlay"; import MobileInterface from "../../../mobile/MobileInterface"; +import "./RadialMenu.scss"; +import { RadialMenuItem, RadialMenuProps } from "./RadialMenuItem"; @observer export class RadialMenu extends React.Component { diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 25775edef..76aa51f63 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -82,8 +82,34 @@ export class CurrentUserUtils { }); } + if (doc["template-button-detail"] === undefined) { + const { TextDocument, ImageDocument, CarouselDocument, TreeDocument } = Docs.Create; + const fallbackImg = "http://www.cs.brown.edu/~bcz/face.gif"; + const detailedTemplate = `{ "doc": { "type": "doc", "content": [ { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "year" } } ] }, { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "company" } } ] } ] }, "selection":{"type":"text","anchor":1,"head":1},"storedMarks":[] }`; + + const textDoc = TextDocument("", { title: "details", _autoHeight: true }); + const detailView = Docs.Create.MultirowDocument([ + CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }), + TreeDocument([ + // textDoc, + TextDocument("", { title: "short description", _autoHeight: true }), + // TreeDocument([], { title: "narratives", _height: 75, treeViewHideTitle: true }), + TextDocument("", { title: "long description", _height: 350 }) + ], { title: "stuff", _height: 100 }) + ], { _chromeStatus: "disabled", _width: 300, _height: 300, _autoHeight: true, title: "detailView" }); + textDoc.data = new RichTextField(detailedTemplate, "year company"); + detailView.isTemplateDoc = makeTemplate(detailView); + + doc["template-button-detail"] = CurrentUserUtils.ficon({ + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + dragFactory: new PrefetchProxy(detailView) as any as Doc, + removeDropProperties: new List(["dropAction"]), title: "detail 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], { + 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, doc["template-button-detail"] as Doc], { title: "Compound Item Creators", _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 }), -- cgit v1.2.3-70-g09d2 From c75ffd4900acea74c55b6bf275a5e8082c15d573 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sun, 26 Apr 2020 19:29:50 -0700 Subject: formatted textbox disposers refactor, paragraph chunked rich text initialization and buxton importer updates --- src/client/documents/Documents.ts | 1 + .../views/collections/CollectionTreeView.tsx | 21 ++++++-- src/client/views/nodes/FormattedTextBox.tsx | 60 ++++++++-------------- src/scraping/buxton/final/BuxtonImporter.ts | 17 +++--- 4 files changed, 49 insertions(+), 50 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 1268c97b0..6bd2eee3c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -407,6 +407,7 @@ export namespace Docs { const doc = StackingDocument(deviceImages, { title: device.title, _LODdisable: true }); const deviceProto = Doc.GetProto(doc); deviceProto.hero = new ImageField(constructed[0].url); + deviceProto.fontFamily = "Arial"; Docs.Get.FromJson({ data: device, appendToExisting: { targetDoc: deviceProto } }); Doc.AddDocToList(parentProto, "data", doc); } else if (errors) { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 7f5dc98f1..49eb90bc2 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -730,18 +730,31 @@ export class CollectionTreeView extends CollectionSubView ({ + type: "paragraph", + content: [{ type: "dashField", attrs: { fieldKey } }] + })) + }, + selection: { type: "text", anchor: 1, head: 1 }, + storedMarks: [] + }; + textDoc.data = new RichTextField(JSON.stringify(detailedTemplate), buxtonFieldKeys.join(" ")); const heroView = ImageDocument(fallbackImg, { title: "heroView", isTemplateDoc: true, isTemplateForField: "hero", }); // this acts like a template doc and a template field ... a little weird, but seems to work? heroView.proto!.layout = ImageBox.LayoutString("hero"); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 425af8ccf..dd0df9f3f 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -83,17 +83,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp private _lastX = 0; private _lastY = 0; private _undoTyping?: UndoManager.Batch; - private _searchReactionDisposer?: Lambda; - private _recordReactionDisposer: Opt; - private _scrollToRegionReactionDisposer: Opt; - private _reactionDisposer: Opt; - private _heightReactionDisposer: Opt; - private _proxyReactionDisposer: Opt; - private _pullReactionDisposer: Opt; - private _pushReactionDisposer: Opt; - private _buttonBarReactionDisposer: Opt; - private _linkMakerDisposer: Opt; - private _scrollDisposer: Opt; + private _disposers: { [name: string]: IReactionDisposer } = {}; private dropDisposer?: DragManager.DragDropDisposer; @computed get _recording() { return this.dataDoc.audioState === "recording"; } @@ -564,7 +554,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } componentDidMount() { - this._buttonBarReactionDisposer = reaction( + this._disposers.buttonBar = reaction( () => DocumentButtonBar.Instance, instance => { if (instance) { @@ -573,7 +563,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } ); - this._linkMakerDisposer = reaction( + this._disposers.linkMaker = reaction( () => this.props.makeLink?.(), (linkDoc: Opt) => { if (linkDoc) { @@ -584,8 +574,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, { fireImmediately: true } ); - - this._reactionDisposer = reaction( + this._disposers.editorState = reaction( () => { if (this.dataDoc[this.props.fieldKey + "-noTemplate"] || !this.props.Document[this.props.fieldKey + "-textTemplate"]) { return Cast(this.dataDoc[this.props.fieldKey], RichTextField, null)?.Data; @@ -600,8 +589,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } ); - - this._pullReactionDisposer = reaction( + this._disposers.pullDoc = reaction( () => this.props.Document[Pulls], () => { if (!DocumentButtonBar.hasPulledHack) { @@ -611,8 +599,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } ); - - this._pushReactionDisposer = reaction( + this._disposers.pushDoc = reaction( () => this.props.Document[Pushes], () => { if (!DocumentButtonBar.hasPushedHack) { @@ -621,19 +608,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } ); - - this._heightReactionDisposer = reaction( + this._disposers.height = reaction( () => [this.layoutDoc[WidthSym](), this.layoutDoc._autoHeight], () => this.tryUpdateHeight() ); this.setupEditor(this.config, this.props.fieldKey); - this._searchReactionDisposer = reaction(() => this.rootDoc.searchMatch, + this._disposers.search = reaction(() => this.rootDoc.searchMatch, search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(), { fireImmediately: true }); - this._recordReactionDisposer = reaction(() => this._recording, + this._disposers.record = reaction(() => this._recording, () => { if (this._recording) { setTimeout(action(() => { @@ -643,8 +629,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } else setTimeout(() => this.stopDictation(true), 0); } ); - - this._scrollToRegionReactionDisposer = reaction( + this._disposers.scrollToRegion = reaction( () => StrCast(this.layoutDoc.scrollToLinkID), async (scrollToLinkID) => { const findLinkFrag = (frag: Fragment, editor: EditorView) => { @@ -689,8 +674,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, { fireImmediately: true } ); - - this._scrollDisposer = reaction(() => NumCast(this.props.Document.scrollPos), + this._disposers.scroll = reaction(() => NumCast(this.props.Document.scrollPos), pos => this._scrollRef.current && this._scrollRef.current.scrollTo({ top: pos }), { fireImmediately: true } ); @@ -876,7 +860,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }); const startupText = !rtfField && this._editorView && Field.toString(this.dataDoc[fieldKey] as Field); if (startupText) { - this._editorView.dispatch(this._editorView.state.tr.insertText(startupText)); + const paragraphSegments = startupText.split("\n\n"); + const { state: { tr }, dispatch } = this._editorView; + if (paragraphSegments.length) { + for (const paragraph of paragraphSegments) { + dispatch(tr.insertText(paragraph)); + } + } else { + dispatch(tr.insertText(startupText)); + } } } @@ -906,17 +898,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } componentWillUnmount() { - this._scrollDisposer?.(); - this._scrollToRegionReactionDisposer?.(); - this._reactionDisposer?.(); - this._proxyReactionDisposer?.(); - this._pushReactionDisposer?.(); - this._pullReactionDisposer?.(); - this._heightReactionDisposer?.(); - this._searchReactionDisposer?.(); - this._recordReactionDisposer?.(); - this._buttonBarReactionDisposer?.(); - this._linkMakerDisposer?.(); + Object.values(this._disposers).forEach(disposer => disposer?.()); this._editorView?.destroy(); } diff --git a/src/scraping/buxton/final/BuxtonImporter.ts b/src/scraping/buxton/final/BuxtonImporter.ts index 122415460..64b988610 100644 --- a/src/scraping/buxton/final/BuxtonImporter.ts +++ b/src/scraping/buxton/final/BuxtonImporter.ts @@ -16,6 +16,7 @@ interface DocumentContents { hyperlinks: string[]; captions: string[]; embeddedFileNames: string[]; + longDescriptionParagraphs: string[]; } export interface DeviceDocument { @@ -186,10 +187,6 @@ const RegexMap = new Map>([ exp: /Short Description:\s+(.*)Bill Buxton[’']s Notes/, transformer: Utilities.correctSentences }], - ["longDescription", { - exp: /Bill Buxton[’']s Notes(.*)Device Details/, - transformer: Utilities.correctSentences - }], ]); const sourceDir = path.resolve(__dirname, "source"); @@ -267,7 +264,12 @@ async function extractFileContents(pathToDocument: string): Promise node.text()); + const captionTargets = document.find(tableCellXPath).map(node => node.text().trim()); + + const paragraphs = document.find('//*[name()="w:p"]').map(node => Utilities.correctSentences(node.text()).transformed!); + const start = paragraphs.indexOf(paragraphs.find(el => /Bill Buxton[’']s Notes/.test(el))!) + 1; + const end = paragraphs.indexOf("Device Details"); + const longDescriptionParagraphs = paragraphs.slice(start, end); const { length } = captionTargets; strictEqual(length > 3, true, "No captions written."); @@ -290,7 +292,7 @@ async function extractFileContents(pathToDocument: string): Promise { } function analyze(fileName: string, contents: DocumentContents): AnalysisResult { - const { body, imageData, captions, hyperlinks, embeddedFileNames } = contents; + const { body, imageData, captions, hyperlinks, embeddedFileNames, longDescriptionParagraphs } = contents; const device: any = { hyperlinks, captions, @@ -376,6 +378,7 @@ function analyze(fileName: string, contents: DocumentContents): AnalysisResult { return { errors }; } + device.longDescription = longDescriptionParagraphs.join("\n\n"); return { device }; } -- cgit v1.2.3-70-g09d2 From fc470b25759e8f051dc527066f9bebcaf5e7707d Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sun, 26 Apr 2020 23:55:23 -0700 Subject: various buxton fixes --- src/client/documents/Documents.ts | 1 - .../views/collections/CollectionTreeView.tsx | 24 ++++++++-------- src/client/views/nodes/DocumentContentsView.tsx | 8 +++--- src/client/views/nodes/FormattedTextBox.tsx | 9 +----- src/scraping/buxton/final/BuxtonImporter.ts | 32 ++++++++++++---------- 5 files changed, 36 insertions(+), 38 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 1651a6d55..5e0890e76 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -408,7 +408,6 @@ export namespace Docs { const doc = StackingDocument(deviceImages, { title: device.title, _LODdisable: true }); const deviceProto = Doc.GetProto(doc); deviceProto.hero = new ImageField(constructed[0].url); - deviceProto.fontFamily = "Arial"; Docs.Get.FromJson({ data: device, appendToExisting: { targetDoc: deviceProto } }); Doc.AddDocToList(parentProto, "data", doc); } else if (errors) { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 362d43ee7..dcb5e116c 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -733,19 +733,21 @@ export class CollectionTreeView extends CollectionSubView { const style: { [key: string]: any } = {}; const divKeys = OmitKeys(this.props, ["children", "htmltag", "RootDoc", "Document", "key", "onInput", "onClick", "__proto__"]).omit; Object.keys(divKeys).map((prop: string) => { - let p = (this.props as any)[prop] as string; + const p = (this.props as any)[prop] as string; const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a propery expression string: { script } into a value return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ self: this.props.RootDoc, this: this.props.Document }).result as string || ""; }; @@ -178,9 +178,9 @@ export class DocumentContentsView extends React.Component 1 ? splits[0] + splits[1].replace(/{([^{}]|(?R))*}/, replacer4) : ""; // might have been more elegant if javascript supported recursive patterns diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 8d4b90c41..d98172823 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -860,15 +860,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }); const startupText = !rtfField && this._editorView && Field.toString(this.dataDoc[fieldKey] as Field); if (startupText) { - const paragraphSegments = startupText.split("\n\n"); const { state: { tr }, dispatch } = this._editorView; - if (paragraphSegments.length) { - for (const paragraph of paragraphSegments) { - dispatch(tr.insertText(paragraph)); - } - } else { - dispatch(tr.insertText(startupText)); - } + dispatch(tr.insertText(startupText)); } } diff --git a/src/scraping/buxton/final/BuxtonImporter.ts b/src/scraping/buxton/final/BuxtonImporter.ts index 64b988610..713207a07 100644 --- a/src/scraping/buxton/final/BuxtonImporter.ts +++ b/src/scraping/buxton/final/BuxtonImporter.ts @@ -16,7 +16,7 @@ interface DocumentContents { hyperlinks: string[]; captions: string[]; embeddedFileNames: string[]; - longDescriptionParagraphs: string[]; + longDescription: string; } export interface DeviceDocument { @@ -269,7 +269,7 @@ async function extractFileContents(pathToDocument: string): Promise Utilities.correctSentences(node.text()).transformed!); const start = paragraphs.indexOf(paragraphs.find(el => /Bill Buxton[’']s Notes/.test(el))!) + 1; const end = paragraphs.indexOf("Device Details"); - const longDescriptionParagraphs = paragraphs.slice(start, end); + const longDescription = paragraphs.slice(start, end).filter(paragraph => paragraph.length).join("\n\n"); const { length } = captionTargets; strictEqual(length > 3, true, "No captions written."); @@ -292,7 +292,7 @@ async function extractFileContents(pathToDocument: string): Promise { const imageEntries = allEntries.filter(name => imageEntry.test(name)); const imageUrls: ImageData[] = []; - for (const mediaPath of imageEntries) { - const getImageStream = () => new Promise((resolve, reject) => { - zip.stream(mediaPath, (error: any, stream: any) => error ? reject(error) : resolve(stream)); - }); + const valid: any[] = []; + + const getImageStream = (mediaPath: string) => new Promise((resolve, reject) => { + zip.stream(mediaPath, (error: any, stream: any) => error ? reject(error) : resolve(stream)); + }); + for (const mediaPath of imageEntries) { const { width, height, type } = await new Promise(async resolve => { const sizeStream = (createImageSizeStream() as PassThrough).on('size', (dimensions: Dimensions) => { readStream.destroy(); resolve(dimensions); }).on("error", () => readStream.destroy()); - const readStream = await getImageStream(); + const readStream = await getImageStream(mediaPath); readStream.pipe(sizeStream); }); - if (Math.abs(width - height) < 10) { - continue; + + if (Math.abs(width - height) > 10) { + valid.push({ width, height, type, mediaPath }); } + } + for (const { type, width, height, mediaPath } of valid) { const generatedFileName = `upload_${Utils.GenerateGuid()}.${type.toLowerCase()}`; - await DashUploadUtils.outputResizedImages(getImageStream, generatedFileName, imageDir); - + await DashUploadUtils.outputResizedImages(() => getImageStream(mediaPath), generatedFileName, imageDir); imageUrls.push({ url: `/files/images/buxton/${generatedFileName}`, nativeWidth: width, @@ -339,11 +343,12 @@ async function writeImages(zip: any): Promise { } function analyze(fileName: string, contents: DocumentContents): AnalysisResult { - const { body, imageData, captions, hyperlinks, embeddedFileNames, longDescriptionParagraphs } = contents; + const { body, imageData, captions, hyperlinks, embeddedFileNames, longDescription } = contents; const device: any = { hyperlinks, captions, embeddedFileNames, + longDescription, __images: imageData }; const errors: { [key: string]: string } = { fileName }; @@ -378,7 +383,6 @@ function analyze(fileName: string, contents: DocumentContents): AnalysisResult { return { errors }; } - device.longDescription = longDescriptionParagraphs.join("\n\n"); return { device }; } -- cgit v1.2.3-70-g09d2 From 436719e0d5f37a46a981287f4c3e903563663567 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Mon, 27 Apr 2020 00:44:23 -0700 Subject: merged detailView templates, now only exists in current_user_utils --- .../views/collections/CollectionTreeView.tsx | 33 +--------------- .../authentication/models/current_user_utils.ts | 44 ++++++++++++++-------- 2 files changed, 30 insertions(+), 47 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index dcb5e116c..d938bd7ad 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -729,39 +729,10 @@ export class CollectionTreeView extends CollectionSubView ({ - type: "paragraph", - content: [{ type: "dashField", attrs: { fieldKey } }] - })) - }, - selection: { type: "text", anchor: 1, head: 1 }, - storedMarks: [] - }; - textDoc.data = new RichTextField(JSON.stringify(detailedTemplate), buxtonFieldKeys.join(" ")); - + const detailView = Cast(Cast(Doc.UserDoc()["template-button-detail"], Doc, null)?.dragFactory, Doc, null); const heroView = ImageDocument(fallbackImg, { title: "heroView", isTemplateDoc: true, isTemplateForField: "hero", }); // this acts like a template doc and a template field ... a little weird, but seems to work? heroView.proto!.layout = ImageBox.LayoutString("hero"); heroView._showTitle = "title"; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 627f3b324..5535f4bcf 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -83,23 +83,35 @@ export class CurrentUserUtils { } if (doc["template-button-detail"] === undefined) { - const { TextDocument, ImageDocument, MasonryDocument, StackingDocument, CarouselDocument, TreeDocument } = Docs.Create; - const detailedTemplate = `{ "doc": { "type": "doc", "content": [ { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "year" } } ] }, { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "company" } } ] } ] }, "selection":{"type":"text","anchor":1,"head":1},"storedMarks":[] }`; - - const textDoc1 = TextDocument("", { title: "shortDescription", treeViewOpen: true, treeViewExpandedView: "layout", _height: 50 }); - const textDoc2 = TextDocument("", { title: "longDescription", treeViewOpen: false, treeViewExpandedView: "layout", _height: 350 }); - const detailView = Docs.Create.StackingDocument([ - CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }), - MasonryDocument([ - textDoc1, - textDoc2, - // TreeDocument([], { title: "narratives", _height: 75, treeViewHideTitle: true }), - ], { title: "stuff", _height: 300, _xMargin: 0, _autoHeight: true, columnWidth: -1, _chromeStatus: "disabled", treeViewHideTitle: true, _pivotField: "title" }) - ], { _chromeStatus: "disabled", _width: 300, _autoHeight: true, _xMargin: 0, _fontFamily: "Comic Sans MS", _fontSize: 12, title: "detailView" }); - textDoc1.text = new RichTextField(detailedTemplate, "year company"); + const { TextDocument, MasonryDocument, CarouselDocument } = Docs.Create; + + const carousel = CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }); + + const short = TextDocument("", { title: "shortDescription", treeViewOpen: true, treeViewExpandedView: "layout", _height: 50 }); + const long = TextDocument("", { title: "longDescription", treeViewOpen: false, treeViewExpandedView: "layout", _height: 350 }); + short.title = "A Short Description"; + long.title = "Long Description"; + + const shared = { _chromeStatus: "disabled", _autoHeight: true, _xMargin: 0 }; + const detailViewOpts = { title: "detailView", _width: 300, _fontFamily: "Arial", _fontSize: 12 }; + const descriptionWrapperOpts = { title: "descriptions", _height: 300, columnWidth: -1, treeViewHideTitle: true, _pivotField: "title" }; + + const descriptionWrapper = MasonryDocument([short, long], { ...shared, ...descriptionWrapperOpts }); + const detailView = Docs.Create.StackingDocument([carousel, descriptionWrapper], { ...shared, ...detailViewOpts }); detailView.isTemplateDoc = makeTemplate(detailView); - textDoc1.title = "A Short Description"; - textDoc2.title = "Long Description"; + + const buxtonFieldKeys = ["year", "originalPrice", "degreesOfFreedom", "company", "attribute", "primaryKey", "secondaryKey", "dimensions"]; + const detailedTemplate = { + doc: { + type: "doc", content: buxtonFieldKeys.map(fieldKey => ({ + type: "paragraph", + content: [{ type: "dashField", attrs: { fieldKey } }] + })) + }, + selection: { type: "text", anchor: 1, head: 1 }, + storedMarks: [] + }; + short.text = new RichTextField(JSON.stringify(detailedTemplate), buxtonFieldKeys.join(" ")); doc["template-button-detail"] = CurrentUserUtils.ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), -- cgit v1.2.3-70-g09d2