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 +++++------ src/client/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 +- 6 files changed, 20 insertions(+), 14 deletions(-) (limited to 'src/client') 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; } -- cgit v1.2.3-70-g09d2 From 8c3c88dec4113b01063e448e0a02d0f0c51ee6ec Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sun, 19 Apr 2020 11:45:42 -0700 Subject: cleanup --- src/client/documents/Documents.ts | 50 +++++++++++++++++++-------------------- src/server/database.ts | 2 -- 2 files changed, 25 insertions(+), 27 deletions(-) (limited to 'src/client') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 968e3d4dc..b528280aa 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -178,7 +178,7 @@ export namespace Docs { }; type TemplateMap = Map; type PrototypeMap = Map; - const data = "data"; + const defaultDataKey = "data"; const TemplateMap: TemplateMap = new Map([ [DocumentType.RTF, { @@ -186,97 +186,97 @@ export namespace Docs { options: { _height: 150, _xMargin: 10, _yMargin: 10 } }], [DocumentType.QUERY, { - layout: { view: QueryBox, dataField: data }, + layout: { view: QueryBox, dataField: defaultDataKey }, options: { _width: 400 } }], [DocumentType.COLOR, { - layout: { view: ColorBox, dataField: data }, + layout: { view: ColorBox, dataField: defaultDataKey }, options: { _nativeWidth: 220, _nativeHeight: 300 } }], [DocumentType.IMG, { - layout: { view: ImageBox, dataField: data }, + layout: { view: ImageBox, dataField: defaultDataKey }, options: {} }], [DocumentType.WEB, { - layout: { view: WebBox, dataField: data }, + layout: { view: WebBox, dataField: defaultDataKey }, options: { _height: 300 } }], [DocumentType.COL, { - layout: { view: CollectionView, dataField: data }, + layout: { view: CollectionView, dataField: defaultDataKey }, options: { _panX: 0, _panY: 0, scale: 1 } // , _width: 500, _height: 500 } }], [DocumentType.KVP, { - layout: { view: KeyValueBox, dataField: data }, + layout: { view: KeyValueBox, dataField: defaultDataKey }, options: { _height: 150 } }], [DocumentType.DOCHOLDER, { - layout: { view: DocHolderBox, dataField: data }, + layout: { view: DocHolderBox, dataField: defaultDataKey }, options: { _height: 250 } }], [DocumentType.VID, { - layout: { view: VideoBox, dataField: data }, + layout: { view: VideoBox, dataField: defaultDataKey }, options: { currentTimecode: 0 }, }], [DocumentType.AUDIO, { - layout: { view: AudioBox, dataField: data }, + layout: { view: AudioBox, dataField: defaultDataKey }, options: { _height: 35, backgroundColor: "lightGray" } }], [DocumentType.PDF, { - layout: { view: PDFBox, dataField: data }, + layout: { view: PDFBox, dataField: defaultDataKey }, options: { curPage: 1 } }], [DocumentType.IMPORT, { - layout: { view: DirectoryImportBox, dataField: data }, + layout: { view: DirectoryImportBox, dataField: defaultDataKey }, options: { _height: 150 } }], [DocumentType.LINK, { - layout: { view: LinkBox, dataField: data }, + layout: { view: LinkBox, dataField: defaultDataKey }, options: { _height: 150 } }], [DocumentType.LINKDB, { data: new List(), - layout: { view: EmptyBox, dataField: data }, + layout: { view: EmptyBox, dataField: defaultDataKey }, options: { childDropAction: "alias", title: "LINK DB" } }], [DocumentType.SCRIPTING, { - layout: { view: ScriptingBox, dataField: data } + layout: { view: ScriptingBox, dataField: defaultDataKey } }], [DocumentType.YOUTUBE, { - layout: { view: YoutubeBox, dataField: data } + layout: { view: YoutubeBox, dataField: defaultDataKey } }], [DocumentType.LABEL, { - layout: { view: LabelBox, dataField: data }, + layout: { view: LabelBox, dataField: defaultDataKey }, }], [DocumentType.BUTTON, { layout: { view: LabelBox, dataField: "onClick" }, }], [DocumentType.SLIDER, { - layout: { view: SliderBox, dataField: data }, + layout: { view: SliderBox, dataField: defaultDataKey }, }], [DocumentType.PRES, { - layout: { view: PresBox, dataField: data }, + layout: { view: PresBox, dataField: defaultDataKey }, options: {} }], [DocumentType.FONTICON, { - layout: { view: FontIconBox, dataField: data }, + layout: { view: FontIconBox, dataField: defaultDataKey }, options: { _width: 40, _height: 40, borderRounding: "100%" }, }], [DocumentType.RECOMMENDATION, { - layout: { view: RecommendationsBox, dataField: data }, + layout: { view: RecommendationsBox, dataField: defaultDataKey }, options: { _width: 200, _height: 200 }, }], [DocumentType.WEBCAM, { - layout: { view: DashWebRTCVideo, dataField: data } + layout: { view: DashWebRTCVideo, dataField: defaultDataKey } }], [DocumentType.PRESELEMENT, { - layout: { view: PresElementBox, dataField: data } + layout: { view: PresElementBox, dataField: defaultDataKey } }], [DocumentType.INK, { - layout: { view: InkingStroke, dataField: data }, + layout: { view: InkingStroke, dataField: defaultDataKey }, options: { backgroundColor: "transparent" } }], [DocumentType.SCREENSHOT, { - layout: { view: ScreenshotBox, dataField: data }, + layout: { view: ScreenshotBox, dataField: defaultDataKey }, }], ]); diff --git a/src/server/database.ts b/src/server/database.ts index 1da31c5ff..ad285765b 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -52,8 +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`); -- 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') 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') 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 abbe0168ae934eb12e3f2f9180e4e7667891ffc9 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 20 Apr 2020 11:11:18 -0400 Subject: fixed deiconify & clipping LOD collections & Paths --- .../views/collections/collectionFreeForm/CollectionFreeFormView.scss | 1 + src/client/views/nodes/DocumentView.tsx | 2 +- src/server/authentication/models/current_user_utils.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/client') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index e1516b468..a00311a9c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -36,6 +36,7 @@ height: 100%; display: flex; align-items: center; + overflow: hidden; .collectionfreeformview-placeholderSpan { font-size: 32; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 196104fe0..8a05cfb0d 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -867,7 +867,7 @@ export class DocumentView extends DocComponent(Docu SelectionManager.SelectDoc(this, false); } }); - const path = this.props.LibraryPath.reduce((p: string, d: Doc) => p + "/" + (Doc.AreProtosEqual(d, (Doc.UserDoc().LibraryBtn as Doc).sourcePanel as Doc) ? "" : d.title), ""); + const path = this.props.LibraryPath.reduce((p: string, d: Doc) => p + "/" + (Doc.AreProtosEqual(d, (Doc.UserDoc()["tabs-button-library"] as Doc).sourcePanel as Doc) ? "" : d.title), ""); cm.addItem({ description: `path: ${path}`, event: () => { this.props.LibraryPath.map(lp => Doc.GetProto(lp).treeViewOpen = lp.treeViewOpen = true); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 85938e026..e99e12a2a 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -141,7 +141,7 @@ export class CurrentUserUtils { if (doc["template-icon-view"] === undefined) { const iconView = Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, - onClick: ScriptField.MakeScript("deiconifyView(this)") + onClick: ScriptField.MakeScript("deiconifyView(self)") }); 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); -- 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') 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') 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') 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 38a0f3f0b690599d72e52456ecfc14c081811e89 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 20 Apr 2020 19:05:05 -0400 Subject: fixed dragging off search result collection --- src/client/views/search/SearchBox.tsx | 19 +++++++----------- src/server/ApiManagers/SearchManager.ts | 35 +++++++++++++++++---------------- 2 files changed, 25 insertions(+), 29 deletions(-) (limited to 'src/client') diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 0947bff8d..f332104fc 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -167,15 +167,7 @@ export class SearchBox extends React.Component { } basicRequireWords(query: string): string { - const oldWords = query.split(" "); - const newWords: string[] = []; - oldWords.forEach(word => { - const newWrd = "+" + word; - newWords.push(newWrd); - }); - query = newWords.join(" "); - - return query; + return query.split(" ").join(" + ").replace(/ + /, ""); } @action @@ -316,10 +308,13 @@ export class SearchBox extends React.Component { private get filterQuery() { const types = this.filterTypes; - const includeDeleted = this.getDataStatus() ? "" : " AND NOT deleted_b:true"; - const includeIcons = this.getDataStatus() ? "" : " AND NOT type_t:fonticonbox"; + const baseExpr = "NOT baseProto_b:true"; + const includeDeleted = this.getDataStatus() ? "" : " NOT deleted_b:true"; + const includeIcons = this.getDataStatus() ? "" : " NOT type_t:fonticonbox"; + const typeExpr = !types ? "" : ` (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})`; // fq: type_t:collection OR {!join from=id to=proto_i}type_t:collection q:text_t:hello - return "NOT baseProto_b:true" + includeDeleted + includeIcons + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})` : ""); + const query = [baseExpr, includeDeleted, includeIcons, typeExpr].join(" AND ").replace(/AND $/, ""); + return query; } getDataStatus() { return this._deletedDocsStatus; } diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts index 5f7d1cf6d..9e1cc120d 100644 --- a/src/server/ApiManagers/SearchManager.ts +++ b/src/server/ApiManagers/SearchManager.ts @@ -1,18 +1,14 @@ -import ApiManager, { Registration } from "./ApiManager"; -import { Method } from "../RouteManager"; -import { Search } from "../Search"; -const findInFiles = require('find-in-files'); +import { exec } from "child_process"; +import { cyan, green, red, yellow } from "colors"; import * as path from 'path'; -import { pathToDirectory, Directory } from "./UploadManager"; -import { red, cyan, yellow, green } from "colors"; -import RouteSubscriber from "../RouteSubscriber"; -import { exec, execSync } from "child_process"; -import { onWindows } from ".."; -import { get } from "request-promise"; import { log_execution } from "../ActionUtilities"; import { Database } from "../database"; -import rimraf = require("rimraf"); -import { mkdirSync, chmod, chmodSync } from "fs"; +import { Method } from "../RouteManager"; +import RouteSubscriber from "../RouteSubscriber"; +import { Search } from "../Search"; +import ApiManager, { Registration } from "./ApiManager"; +import { Directory, pathToDirectory } from "./UploadManager"; +const findInFiles = require('find-in-files'); export class SearchManager extends ApiManager { @@ -48,12 +44,17 @@ export class SearchManager extends ApiManager { res.send([]); return; } - const results = await findInFiles.find({ 'term': q, 'flags': 'ig' }, pathToDirectory(Directory.text), ".txt$"); const resObj: { ids: string[], numFound: number, lines: string[] } = { ids: [], numFound: 0, lines: [] }; - for (const result in results) { - resObj.ids.push(path.basename(result, ".txt").replace(/upload_/, "")); - resObj.lines.push(results[result].line); - resObj.numFound++; + try { + const results = await findInFiles.find({ 'term': q, 'flags': 'ig' }, pathToDirectory(Directory.text), ".txt$"); + for (const result in results) { + resObj.ids.push(path.basename(result, ".txt").replace(/upload_/, "")); + resObj.lines.push(results[result].line); + resObj.numFound++; + } + } + catch (e) { + console.error(e); } res.send(resObj); } -- cgit v1.2.3-70-g09d2 From a9b6fba3a742f95815e2664770079bebd3b87d5f Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 20 Apr 2020 22:34:29 -0400 Subject: fixed search to avoid server crashes by stripping off initial ?*+ characters. made search parameters persistent on queryBox --- src/client/documents/Documents.ts | 1 + src/client/util/SearchUtil.ts | 2 +- src/client/views/nodes/QueryBox.tsx | 13 +++++-- src/client/views/search/IconBar.tsx | 4 +-- src/client/views/search/SearchBox.tsx | 40 +++++++++++----------- src/server/ApiManagers/SearchManager.ts | 17 ++++----- .../authentication/models/current_user_utils.ts | 1 + 7 files changed, 42 insertions(+), 36 deletions(-) (limited to 'src/client') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e3cc8ccfe..5ff8f29ec 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -140,6 +140,7 @@ export interface DocumentOptions { icon?: string; sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script + searchFileTypes?: List; // file types allowed in a search query strokeWidth?: number; treeViewPreventOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expand/collapse state to be independent of other views of the same document in the tree view treeViewHideTitle?: boolean; // whether to hide the title of a tree view diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 2026bf940..6501da34a 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -44,7 +44,7 @@ export namespace SearchUtil { const { ids, highlighting } = result; const txtresult = query !== "*" && JSON.parse(await rp.get(Utils.prepend("/textsearch"), { - qs: { ...options, q: query }, + qs: { ...options, q: query.replace(/^[ \+\?\*\|]*/, "") }, // a leading '+' leads to a server crash since findInFiles doesn't handle regex failures })); const fileids = txtresult ? txtresult.ids : []; diff --git a/src/client/views/nodes/QueryBox.tsx b/src/client/views/nodes/QueryBox.tsx index 947167200..76885eada 100644 --- a/src/client/views/nodes/QueryBox.tsx +++ b/src/client/views/nodes/QueryBox.tsx @@ -3,13 +3,14 @@ import { IReactionDisposer } from "mobx"; import { observer } from "mobx-react"; import { documentSchema } from "../../../new_fields/documentSchemas"; import { Id } from '../../../new_fields/FieldSymbols'; -import { makeInterface } from "../../../new_fields/Schema"; -import { StrCast } from "../../../new_fields/Types"; +import { makeInterface, listSpec } from "../../../new_fields/Schema"; +import { StrCast, Cast } from "../../../new_fields/Types"; import { SelectionManager } from "../../util/SelectionManager"; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { SearchBox } from "../search/SearchBox"; import { FieldView, FieldViewProps } from './FieldView'; import "./QueryBox.scss"; +import { List } from "../../../new_fields/List"; type QueryDocument = makeInterface<[typeof documentSchema]>; const QueryDocument = makeInterface(documentSchema); @@ -28,7 +29,13 @@ export class QueryBox extends ViewBoxAnnotatableComponent e.stopPropagation()} > - + this.dataDoc.searchQuery = q} + searchQuery={StrCast(this.dataDoc.searchQuery)} + setSearchFileTypes={q => this.dataDoc.searchFileTypes = new List(q)} + searchFileTypes={Cast(this.dataDoc.searchFileTypes, listSpec("string"), [])} + filterQquery={StrCast(this.dataDoc.filterQuery)} />
    ; } } \ No newline at end of file diff --git a/src/client/views/search/IconBar.tsx b/src/client/views/search/IconBar.tsx index 9cf5a9c87..9b7cf2fc6 100644 --- a/src/client/views/search/IconBar.tsx +++ b/src/client/views/search/IconBar.tsx @@ -25,7 +25,7 @@ library.add(faGlobeAsia); library.add(faBan); export interface IconBarProps { - setIcons: (icons: string[]) => {}; + setIcons: (icons: string[]) => void; } @@ -44,7 +44,7 @@ export class IconBar extends React.Component { @action.bound updateIcon(newArray: string[]) { - this._icons = newArray; + this._icons = newArray; this.props.setIcons?.(this._icons); } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index f332104fc..b0a49f750 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -19,13 +19,17 @@ import { FieldView } from '../nodes/FieldView'; import { DocumentType } from "../../documents/DocumentTypes"; import { DocumentView } from '../nodes/DocumentView'; import { SelectionManager } from '../../util/SelectionManager'; +import { listSpec } from '../../../new_fields/Schema'; library.add(faTimes); export interface SearchProps { id: string; - searchQuery?: string; + searchQuery: string; filterQquery?: string; + setSearchQuery: (q: string) => {}; + searchFileTypes: string[]; + setSearchFileTypes: (types: string[]) => {} } export enum Keys { @@ -37,7 +41,8 @@ export enum Keys { @observer export class SearchBox extends React.Component { - @observable private _searchString: string = ""; + private get _searchString() { return this.props.searchQuery; } + private set _searchString(value) { this.props.setSearchQuery(value); } @observable private _resultsOpen: boolean = false; @observable private _searchbarOpen: boolean = false; @observable private _results: [Doc, string[], string[]][] = []; @@ -72,20 +77,16 @@ export class SearchBox extends React.Component { this.resultsScrolled = this.resultsScrolled.bind(this); } - componentDidMount = () => { + componentDidMount = action(() => { if (this.inputRef.current) { this.inputRef.current.focus(); - runInAction(() => this._searchbarOpen = true); + this._searchbarOpen = true; } - if (this.props.searchQuery && this.props.filterQquery) { - console.log(this.props.searchQuery); - const sq = this.props.searchQuery; - runInAction(() => { - this._searchString = sq; - this.submitSearch(); - }); + if (this.props.searchQuery) { // bcz: why was this here? } && this.props.filterQquery) { + this._searchString = this.props.searchQuery; + this.submitSearch(); } - } + }) @action @@ -133,7 +134,10 @@ export class SearchBox extends React.Component { //this also serves as an indicator if the word status filter is applied @observable private _filterOpen: boolean = false; //if icons = all icons, then no icon filter is applied - @observable private _icons: string[] = this._allIcons; + get _icons() { return this.props.searchFileTypes; } + set _icons(value) { + this.props.setSearchFileTypes(value); + } //if all of these are true, no key filter is applied @observable private _titleFieldStatus: boolean = true; @observable private _authorFieldStatus: boolean = true; @@ -206,12 +210,6 @@ export class SearchBox extends React.Component { return this._icons.length === this._allIcons.length ? undefined : this._icons; } - @action.bound - updateIcon(newArray: string[]) { this._icons = newArray; } - - @action.bound - getIcons(): string[] { return this._icons; } - //TODO: basically all of this //gets all of the collections of all the docviews that are selected //if a collection is the only thing selected, search only in that collection (not its container) @@ -648,7 +646,9 @@ export class SearchBox extends React.Component {
  • - this._icons = icons} /> + { + this._icons = icons; + }} />
    diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts index 9e1cc120d..753c31fcf 100644 --- a/src/server/ApiManagers/SearchManager.ts +++ b/src/server/ApiManagers/SearchManager.ts @@ -45,16 +45,13 @@ export class SearchManager extends ApiManager { return; } const resObj: { ids: string[], numFound: number, lines: string[] } = { ids: [], numFound: 0, lines: [] }; - try { - const results = await findInFiles.find({ 'term': q, 'flags': 'ig' }, pathToDirectory(Directory.text), ".txt$"); - for (const result in results) { - resObj.ids.push(path.basename(result, ".txt").replace(/upload_/, "")); - resObj.lines.push(results[result].line); - resObj.numFound++; - } - } - catch (e) { - console.error(e); + let results: any; + const dir = pathToDirectory(Directory.text); + results = await findInFiles.find({ 'term': q, 'flags': 'ig' }, dir, ".txt$"); + for (const result in results) { + resObj.ids.push(path.basename(result, ".txt").replace(/upload_/, "")); + resObj.lines.push(results[result].line); + resObj.numFound++; } res.send(resObj); } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index e0ca5a468..3955f64fc 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -413,6 +413,7 @@ export class CurrentUserUtils { _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, + searchFileTypes: new List([DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.VID, DocumentType.WEB, DocumentType.SCRIPTING]), targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, lockedPosition: true, onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel") -- cgit v1.2.3-70-g09d2 From e091a465b860f0b205fbfa5ac6feedaf4f98e1dd Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 21 Apr 2020 01:15:17 -0400 Subject: added MakeClone to alias documents in a collection. fixed embedded custom templates. --- src/client/util/DragManager.ts | 2 +- src/client/util/RichTextSchema.tsx | 10 ++++---- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/search/SearchBox.scss | 3 ++- src/new_fields/Doc.ts | 43 +++++++++++++++++++++++++++++++-- 5 files changed, 50 insertions(+), 10 deletions(-) (limited to 'src/client') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 3ea030171..42a78a4bf 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -205,7 +205,7 @@ export namespace DragManager { e.docDragData && (e.docDragData.droppedDocuments = dragData.draggedDocuments.map(d => !dragData.isSelectionMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) : dragData.userDropAction === "alias" || (!dragData.userDropAction && dragData.dropAction === "alias") ? Doc.MakeAlias(d) : - dragData.userDropAction === "copy" || (!dragData.userDropAction && dragData.dropAction === "copy") ? Doc.MakeCopy(d, true) : d) + dragData.userDropAction === "copy" || (!dragData.userDropAction && dragData.dropAction === "copy") ? Doc.MakeClone(d) : d) ); e.docDragData?.droppedDocuments.forEach((drop: Doc, i: number) => (dragData?.removeDropProperties || []).concat(Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), [])).map(prop => drop[prop] = undefined) diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 0599b3ebe..1522f5e21 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -27,11 +27,11 @@ import ParagraphNodeSpec from "./ParagraphNodeSpec"; import { Transform } from "./Transform"; import React = require("react"); -const - blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], +const + blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], - preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], - brDOM: DOMOutputSpecArray = ["br"], + preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], + brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; // :: Object @@ -853,7 +853,7 @@ export class DashDocView { this._renderDisposer?.(); this._renderDisposer = reaction(() => { if (!Doc.AreProtosEqual(finalLayout, dashDoc)) { - finalLayout.rootDocument = dashDoc.aliasOf; + finalLayout.rootDocument = dashDoc.aliasOf; // bcz: check on this ... why is it here? } const layoutKey = StrCast(finalLayout.layoutKey); const finalKey = layoutKey && StrCast(finalLayout[layoutKey]).split("'")?.[1]; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 8a05cfb0d..286044ab2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -561,7 +561,7 @@ export class DocumentView extends DocComponent(Docu 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().templateButtons, Doc, null)?.data); + const templBtns = DocListCast(Cast(Doc.UserDoc()["template-buttons"], 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); diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss index f0223ca76..bb62113a1 100644 --- a/src/client/views/search/SearchBox.scss +++ b/src/client/views/search/SearchBox.scss @@ -9,7 +9,8 @@ position: absolute; font-size: 10px; line-height: 1; - overflow: auto; + overflow-y: auto; + overflow-x: visible; background: lightgrey, } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 8e8f0928c..5f790f886 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -565,8 +565,9 @@ export namespace Doc { } else if (cfield instanceof ComputedField) { copy[key] = ComputedField.MakeFunction(cfield.script.originalScript); } else if (field instanceof ObjectField) { - copy[key] = key.includes("layout[") && doc[key] instanceof Doc ? Doc.MakeCopy(doc[key] as Doc, false) : - doc[key] instanceof Doc ? doc[key] : ObjectField.MakeCopy(field); + copy[key] = doc[key] instanceof Doc ? + key.includes("layout[") ? Doc.MakeCopy(doc[key] as Doc, false) : doc[key] : // reference documents except copy documents that are expanded teplate fields + ObjectField.MakeCopy(field); } else if (field instanceof Promise) { debugger; //This shouldn't happend... } else { @@ -578,6 +579,44 @@ export namespace Doc { return copy; } + export function MakeClone(doc: Doc, cloneProto: boolean = true): Doc { + const copy = new Doc(undefined, true); + const exclude = Cast(doc.excludeFields, listSpec("string"), []); + Object.keys(doc).forEach(key => { + if (exclude.includes(key)) return; + const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); + const field = ProxyField.WithoutProxy(() => doc[key]); + if (key === "proto" && cloneProto) { + if (doc[key] instanceof Doc) { + copy[key] = Doc.MakeClone(doc[key]!, false); + } + } else { + if (field instanceof RefField) { + copy[key] = field; + } else if (cfield instanceof ComputedField) { + copy[key] = ComputedField.MakeFunction(cfield.script.originalScript); + } else if (field instanceof ObjectField) { + const list = Cast(doc[key], listSpec(Doc)); + if (list !== undefined && !(list instanceof Promise)) { + copy[key] = new List(list.filter(d => d instanceof Doc).map(d => Doc.MakeCopy(d as Doc, false))); + } else { + copy[key] = doc[key] instanceof Doc ? + key.includes("layout[") ? + Doc.MakeCopy(doc[key] as Doc, false) : doc[key] : // reference documents except copy documents that are expanded teplate fields + ObjectField.MakeCopy(field); + } + } else if (field instanceof Promise) { + debugger; //This shouldn't happend... + } else { + copy[key] = field; + } + } + }); + Doc.SetInPlace(copy, "title", "CLONE: " + doc.title, true); + copy.cloneOf = doc; + return copy; + } + export function MakeDelegate(doc: Doc, id?: string, title?: string): Doc; export function MakeDelegate(doc: Opt, id?: string, title?: string): Opt; export function MakeDelegate(doc: Opt, id?: string, title?: string): Opt { -- cgit v1.2.3-70-g09d2 From 0bc20bc8c1f2b6b77624d37047d63a31fa0cf299 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 21 Apr 2020 11:25:30 -0400 Subject: added additional rendition menu item --- src/client/views/collections/CollectionView.tsx | 67 ++++++++++++++----------- 1 file changed, 37 insertions(+), 30 deletions(-) (limited to 'src/client') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 877e4355f..178c3189b 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -192,38 +192,45 @@ export class CollectionView extends Touchable { } + setupViewTypes(category: string, func: (viewType: CollectionViewType) => Doc, addExtras: boolean) { + const existingVm = ContextMenu.Instance.findByDescription(category); + const subItems = existingVm && "subitems" in existingVm ? existingVm.subitems : []; + + subItems.push({ description: "Freeform", event: () => func(CollectionViewType.Freeform), icon: "signature" }); + if (addExtras && CollectionView._safeMode) { + ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => func(CollectionViewType.Invalid), icon: "project-diagram" }); + } + subItems.push({ description: "Schema", event: () => func(CollectionViewType.Schema), icon: "th-list" }); + subItems.push({ description: "Treeview", event: () => func(CollectionViewType.Tree), icon: "tree" }); + subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking), icon: "ellipsis-v" }); + subItems.push({ description: "Stacking (AutoHeight)", event: () => func(CollectionViewType.Stacking)._autoHeight = true, icon: "ellipsis-v" }); + subItems.push({ description: "Staff", event: () => func(CollectionViewType.Staff), icon: "music" }); + subItems.push({ description: "Multicolumn", event: () => func(CollectionViewType.Multicolumn), icon: "columns" }); + subItems.push({ description: "Multirow", event: () => func(CollectionViewType.Multirow), icon: "columns" }); + subItems.push({ description: "Masonry", event: () => func(CollectionViewType.Masonry), icon: "columns" }); + subItems.push({ description: "Carousel", event: () => func(CollectionViewType.Carousel), icon: "columns" }); + subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" }); + subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" }); + if (addExtras) switch (this.props.Document._viewType) { + case CollectionViewType.Freeform: { + subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) }); + break; + } + } + addExtras && subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" }); + !existingVm && ContextMenu.Instance.addItem({ description: category, subitems: subItems, icon: "eye" }); + } + onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - const existingVm = ContextMenu.Instance.findByDescription("View Modes..."); - const subItems = existingVm && "subitems" in existingVm ? existingVm.subitems : []; - subItems.push({ description: "Freeform", event: () => { this.props.Document._viewType = CollectionViewType.Freeform; }, icon: "signature" }); - if (CollectionView._safeMode) { - ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => this.props.Document._viewType = CollectionViewType.Invalid, icon: "project-diagram" }); - } - subItems.push({ description: "Schema", event: () => this.props.Document._viewType = CollectionViewType.Schema, icon: "th-list" }); - subItems.push({ description: "Treeview", event: () => this.props.Document._viewType = CollectionViewType.Tree, icon: "tree" }); - subItems.push({ description: "Stacking", event: () => this.props.Document._viewType = CollectionViewType.Stacking, icon: "ellipsis-v" }); - subItems.push({ - description: "Stacking (AutoHeight)", event: () => { - this.props.Document._viewType = CollectionViewType.Stacking; - this.props.Document._autoHeight = true; - }, icon: "ellipsis-v" - }); - subItems.push({ description: "Staff", event: () => this.props.Document._viewType = CollectionViewType.Staff, icon: "music" }); - subItems.push({ description: "Multicolumn", event: () => this.props.Document._viewType = CollectionViewType.Multicolumn, icon: "columns" }); - subItems.push({ description: "Multirow", event: () => this.props.Document._viewType = CollectionViewType.Multirow, icon: "columns" }); - subItems.push({ description: "Masonry", event: () => this.props.Document._viewType = CollectionViewType.Masonry, icon: "columns" }); - subItems.push({ description: "Carousel", event: () => this.props.Document._viewType = CollectionViewType.Carousel, icon: "columns" }); - subItems.push({ description: "Pivot/Time", event: () => this.props.Document._viewType = CollectionViewType.Time, icon: "columns" }); - subItems.push({ description: "Map", event: () => this.props.Document._viewType = CollectionViewType.Map, icon: "globe-americas" }); - switch (this.props.Document._viewType) { - case CollectionViewType.Freeform: { - subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) }); - break; - } - } - subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" }); - !existingVm && ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems, icon: "eye" }); + + this.setupViewTypes("View Modes ...", (vtype => { this.props.Document._viewType = vtype; return this.props.Document; }), true); + this.setupViewTypes("Additional Rendition ...", vtype => { + const newRendition = Doc.MakeAlias(this.props.Document); + newRendition._viewType = vtype; + this.props.addDocTab(newRendition, "onRight"); + return newRendition; + }, false); const existing = ContextMenu.Instance.findByDescription("Layout..."); const layoutItems = existing && "subitems" in existing ? existing.subitems : []; -- cgit v1.2.3-70-g09d2 From 3d629495644631e6b614b1b48f1d32d6c7aeefc6 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 21 Apr 2020 17:25:17 -0400 Subject: added parameterization capability to layout strings. added Div's that can take Dash field values --- src/client/util/RichTextSchema.tsx | 6 ++-- src/client/views/DocumentDecorations.tsx | 4 +-- src/client/views/collections/CollectionView.tsx | 7 ++-- src/client/views/nodes/DocumentContentsView.tsx | 45 +++++++++++++++++++++---- 4 files changed, 46 insertions(+), 16 deletions(-) (limited to 'src/client') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 1522f5e21..d23962d5c 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -852,9 +852,9 @@ export class DashDocView { }; this._renderDisposer?.(); this._renderDisposer = reaction(() => { - if (!Doc.AreProtosEqual(finalLayout, dashDoc)) { - finalLayout.rootDocument = dashDoc.aliasOf; // bcz: check on this ... why is it here? - } + // if (!Doc.AreProtosEqual(finalLayout, dashDoc)) { + // finalLayout.rootDocument = dashDoc.aliasOf; // bcz: check on this ... why is it here? + // } const layoutKey = StrCast(finalLayout.layoutKey); const finalKey = layoutKey && StrCast(finalLayout[layoutKey]).split("'")?.[1]; if (finalLayout !== dashDoc && finalKey) { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index c8766a6b3..bd41788d4 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -3,7 +3,7 @@ import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faT import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DataSym } from "../../new_fields/Doc"; +import { Doc, DataSym, Field } from "../../new_fields/Doc"; import { PositionDocument } from '../../new_fields/documentSchemas'; import { ScriptField } from '../../new_fields/ScriptField'; import { Cast, StrCast, NumCast } from "../../new_fields/Types"; @@ -366,7 +366,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })!.script.run({ self: selected.rootDoc, this: selected.layoutDoc }, console.log).result?.toString() || ""; } if (this._titleControlString.startsWith("#")) { - return selected.props.Document[this._titleControlString.substring(1)]?.toString() || "-unset-"; + return Field.toString(selected.props.Document[this._titleControlString.substring(1)] as Field) || "-unset-"; } return this._accumulatedTitle; } else if (SelectionManager.SelectedDocuments().length > 1) { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 178c3189b..4448fcf21 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -211,11 +211,8 @@ export class CollectionView extends Touchable { subItems.push({ description: "Carousel", event: () => func(CollectionViewType.Carousel), icon: "columns" }); subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" }); subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" }); - if (addExtras) switch (this.props.Document._viewType) { - case CollectionViewType.Freeform: { - subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) }); - break; - } + if (addExtras && this.props.Document._viewType === CollectionViewType.Freeform) { + subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) }); } addExtras && subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" }); !existingVm && ContextMenu.Instance.addItem({ description: category, subitems: subItems, icon: "eye" }); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 7522af3a3..765416658 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -1,8 +1,8 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; -import { Doc, Opt } from "../../../new_fields/Doc"; -import { Cast, StrCast } from "../../../new_fields/Types"; -import { OmitKeys, Without } from "../../../Utils"; +import { Doc, Opt, Field } from "../../../new_fields/Doc"; +import { Cast, StrCast, NumCast } from "../../../new_fields/Types"; +import { OmitKeys, Without, emptyPath } from "../../../Utils"; import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; @@ -53,6 +53,31 @@ class ObserverJsxParser1 extends JsxParser { const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any; + +interface DivProps { + Document: Doc; +} + +@observer +export class Div extends React.Component { + render() { + const style: { [key: string]: any } = {}; + const divKeys = OmitKeys(this.props, ["children", "Document", "key", "__proto__"]).omit; + Object.keys(divKeys).map((prop: string) => { + let p = (this.props as any)[prop] as string; + if (p?.startsWith("@")) { // bcz: extend this to support expression -- is this really a script? + const key = p.substring(1); + const n = Cast(this.props.Document[key], "number", null); + p = n ? n.toString() : StrCast(this.props.Document[key], p); + } + style[prop] = p; + }); + return
    + {this.props.children} +
    ; + } +} + @observer export class DocumentContentsView extends React.Component boolean, @@ -102,21 +127,29 @@ export class DocumentContentsView extends React.Component 12 || !this.layout || !this.layoutDoc) ? (null) : + let layoutFrame = this.layout; + const replacer = (match: any, p1: string, offset: any, string: any) => { + const n = Cast(this.props.Document[p1], "number", null); + return n !== undefined ? n.toString() : StrCast(this.props.Document[p1], p1); + }; + layoutFrame = layoutFrame.replace(/\{([a-zA-Z0-9_-]+)\}/g, replacer); + return (this.props.renderDepth > 12 || !layoutFrame || !this.layoutDoc) ? (null) : this.props.forceLayout === "FormattedTextBox" && this.props.forceFieldKey ? : { console.log(test); }} -- cgit v1.2.3-70-g09d2 From 1808f23e8e72cfca8517d3788f9f89ec989f1062 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 21 Apr 2020 22:09:18 -0400 Subject: functional version of html tags in layout strings including scripts. --- src/client/views/nodes/DocumentContentsView.tsx | 58 ++++++++++++++++++------- 1 file changed, 42 insertions(+), 16 deletions(-) (limited to 'src/client') diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 765416658..d577068b7 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -37,6 +37,8 @@ import React = require("react"); import { RecommendationsBox } from "../RecommendationsBox"; import { TraceMobx } from "../../../new_fields/util"; +import { ScriptField } from "../../../new_fields/ScriptField"; +import ReactTable from "react-table"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? type BindingProps = Without; @@ -54,27 +56,38 @@ class ObserverJsxParser1 extends JsxParser { const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any; -interface DivProps { +interface HTMLtagProps { Document: Doc; + htmltag: string; } - +//" this.bannerColor=this.bannerColor==='red'?'green':'red'} width='100%' height='100%' transform='rotate({2*this.x+this.y}deg)' backgroundColor='{this.bannerColor}'>{this.title}" @observer -export class Div extends React.Component { +export class HTMLtag extends React.Component { + click = (e: React.MouseEvent) => { + const clickScript = (this.props as any).onClick; + ScriptField.MakeScript(clickScript, { self: Doc.name, this: Doc.name })?.script.run({ this: this.props.Document }); + } render() { const style: { [key: string]: any } = {}; - const divKeys = OmitKeys(this.props, ["children", "Document", "key", "__proto__"]).omit; + const divKeys = OmitKeys(this.props, ["children", "htmltag", "Document", "key", "onClick", "__proto__"]).omit; Object.keys(divKeys).map((prop: string) => { let p = (this.props as any)[prop] as string; - if (p?.startsWith("@")) { // bcz: extend this to support expression -- is this really a script? - const key = p.substring(1); + const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: extend this to support expression -- is this really a script? + return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ this: this.props.Document }).result as string || ""; + }; + p = p?.replace(/{([^.'][^}']+)}/g, replacer); + + const replacer2 = (match: any, key: string, offset: any, string: any) => { // bcz: extend this to support expression -- is this really a script? const n = Cast(this.props.Document[key], "number", null); - p = n ? n.toString() : StrCast(this.props.Document[key], p); - } - style[prop] = p; + return n ? n.toString() : StrCast(this.props.Document[key], p); + }; + style[prop] = p?.replace(/@([a-zA-Z0-9-_]+)/g, replacer2); + }); - return
    + const Tag = this.props.htmltag as keyof JSX.IntrinsicElements; + return {this.props.children} -
    ; + ; } } @@ -128,11 +141,24 @@ export class DocumentContentsView extends React.Component { - const n = Cast(this.props.Document[p1], "number", null); - return n !== undefined ? n.toString() : StrCast(this.props.Document[p1], p1); + // replace code content with a script >{content}< as in {this.title} + const replacer = (match: any, expr: string, offset: any, string: any) => { + return ">" + (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ this: this.props.Document }).result as string || "") + "<"; }; - layoutFrame = layoutFrame.replace(/\{([a-zA-Z0-9_-]+)\}/g, replacer); + layoutFrame = layoutFrame.replace(/>\{([^.'][^<}]+)\} with corresponding HTML tag as in: becomes + const replacer2 = (match: any, p1: string, offset: any, string: any) => { + return ` with as in: becomes + const replacer3 = (match: any, p1: string, offset: any, string: any) => { + return ` 12 || !layoutFrame || !this.layoutDoc) ? (null) : this.props.forceLayout === "FormattedTextBox" && this.props.forceFieldKey ? @@ -146,7 +172,7 @@ export class DocumentContentsView extends React.Component Date: Tue, 21 Apr 2020 23:50:20 -0400 Subject: tweaked HTMLtag syntax slightly for onClick functions to be specified without quotes --- package-lock.json | 27 ++++++++++++++++++ package.json | 2 ++ .../collectionFreeForm/CollectionFreeFormView.tsx | 1 - src/client/views/nodes/DocumentContentsView.tsx | 32 ++++++++++++++++------ src/client/views/search/SearchBox.tsx | 4 +-- 5 files changed, 54 insertions(+), 12 deletions(-) (limited to 'src/client') diff --git a/package-lock.json b/package-lock.json index 940321132..176d1f27e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,15 @@ "regenerator-runtime": "^0.13.4" } }, + "@babel/runtime-corejs3": { + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.9.2.tgz", + "integrity": "sha512-HHxmgxbIzOfFlZ+tdeRKtaxWOMUoCG5Mu3wKeUmOxjYrwb3AAHgnmtCUbPPK11/raIWLIBK250t8E2BPO0p7jA==", + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + } + }, "@babel/types": { "version": "7.9.5", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", @@ -1194,6 +1203,11 @@ "resolved": "https://registry.npmjs.org/@types/word-extractor/-/word-extractor-0.3.0.tgz", "integrity": "sha512-XcVsLXMpPT6Lv4Qvsc2yPoWg3zPVKEIyQ21eQ1ka58zZjtd7vUZ2kx0KydRbsNRNGopEIiwlemGzgo46dytR2Q==" }, + "@types/xregexp": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@types/xregexp/-/xregexp-4.3.0.tgz", + "integrity": "sha512-3gJTS9gt27pS7U9q5IVqo4YvKSlkf2ck8ish6etuDj6LIRxkL/2Y8RMUtK/QzvE1Yv2zwWV5yemI2BS0GGGFnA==" + }, "@types/yargs": { "version": "13.0.8", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", @@ -3456,6 +3470,11 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" }, + "core-js-pure": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz", + "integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -18092,6 +18111,14 @@ "resolved": "https://registry.npmjs.org/xoauth2/-/xoauth2-1.2.0.tgz", "integrity": "sha1-8u76wRRyyXHqO8RuVU60sSMhRuU=" }, + "xregexp": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz", + "integrity": "sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==", + "requires": { + "@babel/runtime-corejs3": "^7.8.3" + } + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index ed846fcff..f1b4be520 100644 --- a/package.json +++ b/package.json @@ -127,6 +127,7 @@ "@types/uuid": "^3.4.6", "@types/webpack": "^4.41.3", "@types/word-extractor": "^0.3.0", + "@types/xregexp": "^4.3.0", "@types/youtube": "0.0.38", "adm-zip": "^0.4.13", "archiver": "^3.1.1", @@ -258,6 +259,7 @@ "word-extractor": "^0.3.0", "words-to-numbers": "^1.5.1", "xoauth2": "^1.2.0", + "xregexp": "^4.3.0", "youtube": "^0.1.0" } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d2106808e..3b5101a4d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -44,7 +44,6 @@ import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import { CollectionViewType } from "../CollectionView"; -import { Script } from "vm"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index d577068b7..b5af68ba1 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -35,10 +35,10 @@ import { WebBox } from "./WebBox"; import { InkingStroke } from "../InkingStroke"; import React = require("react"); import { RecommendationsBox } from "../RecommendationsBox"; - import { TraceMobx } from "../../../new_fields/util"; import { ScriptField } from "../../../new_fields/ScriptField"; -import ReactTable from "react-table"; +import XRegExp = require("xregexp"); + const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? type BindingProps = Without; @@ -59,13 +59,13 @@ const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any; interface HTMLtagProps { Document: Doc; htmltag: string; + onClick?: ScriptField; } -//" this.bannerColor=this.bannerColor==='red'?'green':'red'} width='100%' height='100%' transform='rotate({2*this.x+this.y}deg)' backgroundColor='{this.bannerColor}'>{this.title}" -@observer +//"{this.title}"@observer export class HTMLtag extends React.Component { click = (e: React.MouseEvent) => { - const clickScript = (this.props as any).onClick; - ScriptField.MakeScript(clickScript, { self: Doc.name, this: Doc.name })?.script.run({ this: this.props.Document }); + const clickScript = (this.props as any).onClick as Opt; + clickScript?.script.run({ this: this.props.Document }); } render() { const style: { [key: string]: any } = {}; @@ -129,11 +129,12 @@ export class DocumentContentsView extends React.Component): JsxBindings { const list = { ...OmitKeys(this.props, ['parentActive'], (obj: any) => obj.active = this.props.parentActive).omit, Document: this.layoutDoc, DataDoc: this.dataDoc, + onClick: onClick }; return { props: list }; } @@ -141,6 +142,7 @@ export class DocumentContentsView extends React.Component{content}< as in {this.title} const replacer = (match: any, expr: string, offset: any, string: any) => { return ">" + (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ this: this.props.Document }).result as string || "") + "<"; @@ -159,9 +161,21 @@ export class DocumentContentsView extends React.Component; + if (splits.length > 1) { + const code = XRegExp.matchRecursive(splits[1], "{", "}", "", { valueNames: ["between", "left", "match", "right", "between"] }); + layoutFrame = splits[0] + " onClick={props.onClick} " + splits[1].substring(code[1].end + 1); + onClick = ScriptField.MakeScript(code[1].value, { this: Doc.name, self: Doc.name }); + } + + const bindings = this.CreateBindings(onClick); + // layoutFrame = splits.length > 1 ? splits[0] + splits[1].replace(/{([^{}]|(?R))*}/, replacer4) : ""; // might have been more elegant if javascript supported recursive patterns + return (this.props.renderDepth > 12 || !layoutFrame || !this.layoutDoc) ? (null) : this.props.forceLayout === "FormattedTextBox" && this.props.forceFieldKey ? - + : {}; searchFileTypes: string[]; - setSearchFileTypes: (types: string[]) => {} + setSearchFileTypes: (types: string[]) => {}; } export enum Keys { @@ -86,7 +86,7 @@ export class SearchBox extends React.Component { this._searchString = this.props.searchQuery; this.submitSearch(); } - }) + }); @action -- cgit v1.2.3-70-g09d2 From f8019f3894cfcff29318a95d8c71a033de7a2ac6 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 22 Apr 2020 00:20:10 -0400 Subject: fixed div content scripts --- src/client/views/nodes/DocumentContentsView.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client') diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index b5af68ba1..bc8bf3ba2 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -144,10 +144,10 @@ export class DocumentContentsView extends React.Component{content}< as in {this.title} - const replacer = (match: any, expr: string, offset: any, string: any) => { - return ">" + (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ this: this.props.Document }).result as string || "") + "<"; + const replacer = (match: any, prefix: string, expr: string, postfix: string, offset: any, string: any) => { + return prefix + (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ this: this.props.Document }).result as string || "") + postfix; }; - layoutFrame = layoutFrame.replace(/>\{([^.'][^<}]+)\}[^{]*)\{([^.'][^<}]+)\}([^}]*<)/g, replacer); // replace HTML with corresponding HTML tag as in: becomes const replacer2 = (match: any, p1: string, offset: any, string: any) => { -- cgit v1.2.3-70-g09d2 From 3a118ee726355197bb37910785e69d75033c2f43 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 22 Apr 2020 00:22:34 -0400 Subject: oops. --- src/client/views/nodes/DocumentContentsView.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src/client') diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index bc8bf3ba2..a022f2e02 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -62,6 +62,7 @@ interface HTMLtagProps { onClick?: ScriptField; } //"{this.title}"@observer +@observer export class HTMLtag extends React.Component { click = (e: React.MouseEvent) => { const clickScript = (this.props as any).onClick as Opt; -- cgit v1.2.3-70-g09d2 From 30db3b71d3661d7cd41ed32f4004069cb10ec2b4 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 22 Apr 2020 12:31:40 -0400 Subject: added raw text field for PDFs. fixed search scrolling in text boxes. --- src/client/views/collections/CollectionSubView.tsx | 1 + src/client/views/nodes/FormattedTextBox.tsx | 13 +++++-------- src/server/DashUploadUtils.ts | 7 ++++--- src/server/SharedMediaTypes.ts | 1 + 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src/client') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 37cf942c6..ca38a21b8 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -388,6 +388,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: continue; } const proto = Doc.GetProto(doc); + proto.text = result.rawText; proto.fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, ""); if (Upload.isImageInformation(result)) { proto["data-nativeWidth"] = (result.nativeWidth > result.nativeHeight) ? 400 * result.nativeWidth / result.nativeHeight : 400; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 62911dc5c..c8eb4c23c 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -596,7 +596,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.setupEditor(this.config, this.props.fieldKey); - this._searchReactionDisposer = reaction(() => this.layoutDoc.searchMatch, + this._searchReactionDisposer = reaction(() => this.rootDoc.searchMatch, search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(), { fireImmediately: true }); @@ -821,13 +821,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this._editorView = new EditorView(this.ProseRef, { state: rtfField?.Data ? EditorState.fromJSON(config, JSON.parse(rtfField.Data)) : EditorState.create(config), handleScrollToSelection: (editorView) => { - const ref = editorView.domAtPos(editorView.state.selection.from); - let refNode = ref.node as any; - while (refNode && !("getBoundingClientRect" in refNode)) refNode = refNode.parentElement; - const r1 = refNode?.getBoundingClientRect(); - const r3 = self._ref.current!.getBoundingClientRect(); - if (r1.top < r3.top || r1.top > r3.bottom) { - r1 && (self._scrollRef.current!.scrollTop += (r1.top - r3.top) * self.props.ScreenToLocalTransform().Scale); + const docPos = editorView.coordsAtPos(editorView.state.selection.from); + const viewRect = self._ref.current!.getBoundingClientRect(); + if (docPos.top < viewRect.top || docPos.top > viewRect.bottom) { + docPos && (self._scrollRef.current!.scrollTop += (docPos.top - viewRect.top) * self.props.ScreenToLocalTransform().Scale); } return true; }, diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 9b518749c..3f903a861 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -100,7 +100,7 @@ export namespace DashUploadUtils { const writeStream = createWriteStream(serverPathToFile(Directory.text, textFilename)); writeStream.write(result.text, error => error ? reject(error) : resolve()); }); - return MoveParsedFile(file, Directory.pdfs); + return MoveParsedFile(file, Directory.pdfs, undefined, result.text); } const manualSuffixes = [".webm"]; @@ -237,7 +237,7 @@ export namespace DashUploadUtils { * @param suffix If the file doesn't have a suffix and you want to provide it one * to appear in the new location */ - export async function MoveParsedFile(file: File, destination: Directory, suffix: string | undefined = undefined): Promise { + export async function MoveParsedFile(file: File, destination: Directory, suffix: string | undefined = undefined, text?: string): Promise { const { path: sourcePath } = file; let name = path.basename(sourcePath); suffix && (name += suffix); @@ -249,7 +249,8 @@ export namespace DashUploadUtils { result: error ? error : { accessPaths: { agnostic: getAccessPaths(destination, name) - } + }, + rawText: text } }); }); diff --git a/src/server/SharedMediaTypes.ts b/src/server/SharedMediaTypes.ts index 2495123b7..0f788f6c5 100644 --- a/src/server/SharedMediaTypes.ts +++ b/src/server/SharedMediaTypes.ts @@ -21,6 +21,7 @@ export namespace Upload { export interface FileInformation { accessPaths: AccessPathInfo; + rawText?: string; } export type FileResponse = { source: File, result: T | Error }; -- cgit v1.2.3-70-g09d2 From 04bc902ad31eaf07e3a5edc34854744a88ffb3bc Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 22 Apr 2020 14:08:19 -0400 Subject: fixed clicking gear icon on doc decorations. moved repl to Drag items. Removed Open... menu. Added Open FIelds & Full SCreen to Open New Persepectives. --- src/client/views/DocumentDecorations.tsx | 4 ++-- src/client/views/MainView.tsx | 3 ++- src/client/views/OverlayView.tsx | 6 +++++- src/client/views/collections/CollectionView.tsx | 8 ++------ src/client/views/nodes/DocumentView.tsx | 11 ++--------- src/server/authentication/models/current_user_utils.ts | 9 +++++---- 6 files changed, 18 insertions(+), 23 deletions(-) (limited to 'src/client') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index bd41788d4..5d6242201 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -144,8 +144,8 @@ 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.className !== "jsx-parser") child = child.children[0]; - simulateMouseClick(child.children[0], e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); + while (child.children.length) child = child.children[0]; + simulateMouseClick(child, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); } } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index f8e246315..8fb67c435 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, 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 { faTerminal, faCalculator, 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'; @@ -103,6 +103,7 @@ export class MainView extends React.Component { } library.add(faTerminal); + library.add(faCalculator); library.add(faWindowMaximize); library.add(faFileAlt); library.add(faAddressCard); diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 614217bc8..20aa14f84 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -9,6 +9,8 @@ import { Transform } from "../util/Transform"; import { CollectionFreeFormLinksView } from "./collections/collectionFreeForm/CollectionFreeFormLinksView"; import { DocumentView } from "./nodes/DocumentView"; import './OverlayView.scss'; +import { Scripting } from "../util/Scripting"; +import { ScriptingRepl } from './ScriptingRepl'; export type OverlayDisposer = () => void; @@ -210,4 +212,6 @@ export class OverlayView extends React.Component {
    ); } -} \ No newline at end of file +} +// bcz: ugh ... want to be able to pass ScriptingRepl as tag argument, but that doesn't seem to work.. runtime error +Scripting.addGlobal(function addOverlayWindow(Tag: string, options: OverlayElementOptions) { const x = ; OverlayView.Instance.addWindow(x, options); }); \ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 4448fcf21..ade54f2c9 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -221,8 +221,8 @@ export class CollectionView extends Touchable { onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - this.setupViewTypes("View Modes ...", (vtype => { this.props.Document._viewType = vtype; return this.props.Document; }), true); - this.setupViewTypes("Additional Rendition ...", vtype => { + this.setupViewTypes("Change Perspective...", (vtype => { this.props.Document._viewType = vtype; return this.props.Document; }), true); + this.setupViewTypes("Open New Perspective...", vtype => { const newRendition = Doc.MakeAlias(this.props.Document); newRendition._viewType = vtype; this.props.addDocTab(newRendition, "onRight"); @@ -242,10 +242,6 @@ export class CollectionView extends Touchable { !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" }); - const open = ContextMenu.Instance.findByDescription("Open..."); - const openItems = open && "subitems" in open ? open.subitems : []; - !open && ContextMenu.Instance.addItem({ description: "Open...", subitems: openItems, icon: "hand-point-right" }); - const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; const funcs = [{ key: "onChildClick", name: "On Child Clicked", script: undefined as any as ScriptField }]; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 286044ab2..d8783c458 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -40,8 +40,6 @@ import { DocComponent } from "../DocComponent"; import { EditableView } from '../EditableView'; import { InkingControl } from '../InkingControl'; import { KeyphraseQueryView } from '../KeyphraseQueryView'; -import { OverlayView } from '../OverlayView'; -import { ScriptingRepl } from '../ScriptingRepl'; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import { RadialMenu } from './RadialMenu'; @@ -737,17 +735,12 @@ export class DocumentView extends DocComponent(Docu layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); !existing && cm.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" }); - const open = ContextMenu.Instance.findByDescription("Open..."); + const open = cm.findByDescription("Open New Perspective..."); const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; openItems.push({ description: "Open Full Screen", event: () => CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(this, this.props.LibraryPath), icon: "desktop" }); - openItems.push({ description: "Open Tab ", event: () => this.props.addDocTab(this.props.Document, "inTab", this.props.LibraryPath), icon: "folder" }); - openItems.push({ description: "Open Right ", event: () => this.props.addDocTab(this.props.Document, "onRight", this.props.LibraryPath), icon: "caret-square-right" }); - openItems.push({ description: "Open Alias Tab ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "inTab"), icon: "folder" }); - openItems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "caret-square-right" }); openItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); templateDoc && openItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" }); - openItems.push({ description: "Open Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); - !open && cm.addItem({ description: "Open...", subitems: openItems, icon: "external-link-alt" }); + !open && cm.addItem({ description: "Open New Perspective...", subitems: openItems, icon: "external-link-alt" }); const existingOnClick = cm.findByDescription("OnClick..."); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 3955f64fc..b4f9ead53 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -84,7 +84,7 @@ 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 Item Creators", _xMargin: 0, _showTitle: "title", + 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 }), })); @@ -186,6 +186,7 @@ export class CurrentUserUtils { { 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().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" })' }, { 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' }, @@ -194,10 +195,10 @@ export class CurrentUserUtils { // { 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()" }, + { title: "Drag a Calculator REPL", label: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' }, ]; + } // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools @@ -229,7 +230,7 @@ export class CurrentUserUtils { if (dragCreatorSet === undefined) { doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, { - title: "Standard Item Creators", _showTitle: "title", _xMargin: 0, + title: "Basic 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 }), })); -- cgit v1.2.3-70-g09d2 From 2d44b804d3029e5f99bfe37310651aa12e69f3fc Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 22 Apr 2020 17:19:34 -0400 Subject: extended links to support a draw all the time flag. fixed parentdocseletor to update when inputs change. --- src/client/views/collections/ParentDocumentSelector.tsx | 13 +++++++------ .../collectionFreeForm/CollectionFreeFormLinkView.tsx | 5 +++-- .../collectionFreeForm/CollectionFreeFormLinksView.tsx | 4 ++-- src/client/views/nodes/LinkAnchorBox.tsx | 3 ++- 4 files changed, 14 insertions(+), 11 deletions(-) (limited to 'src/client') diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 5c9d2b0dd..10c6ead1a 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import './ParentDocumentSelector.scss'; import { Doc } from "../../../new_fields/Doc"; import { observer } from "mobx-react"; -import { observable, action, runInAction, trace, computed } from "mobx"; +import { observable, action, runInAction, trace, computed, reaction, IReactionDisposer } from "mobx"; import { Id } from "../../../new_fields/FieldSymbols"; import { SearchUtil } from "../../util/SearchUtil"; import { CollectionDockingView } from "./CollectionDockingView"; @@ -31,13 +31,14 @@ type SelectorProps = { export class SelectorContextMenu extends React.Component { @observable private _docs: { col: Doc, target: Doc }[] = []; @observable private _otherDocs: { col: Doc, target: Doc }[] = []; + _reaction: IReactionDisposer | undefined; - constructor(props: SelectorProps) { - super(props); - - this.fetchDocuments(); + componentDidMount() { + this._reaction = reaction(() => this.props.Document, () => this.fetchDocuments(), { fireImmediately: true }); + } + componentWillUnmount() { + this._reaction?.(); } - async fetchDocuments() { const aliases = (await SearchUtil.GetAliasesOfDocument(this.props.Document)).filter(doc => doc !== this.props.Document); const { docs } = await SearchUtil.Search("", true, { fq: `data_l:"${this.props.Document[Id]}"` }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 09fc5148e..b2ea7290d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -25,7 +25,7 @@ export class CollectionFreeFormLinkView extends React.Component [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform(), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document)], action(() => { setTimeout(action(() => this._opacity = 1), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render() - setTimeout(action(() => this._opacity = 0.05), 750); // this will unhighlight the link line. + setTimeout(action(() => (!this.props.LinkDocs.length || !this.props.LinkDocs[0].linkDisplay) && (this._opacity = 0.05)), 750); // this will unhighlight the link line. const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : []; const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : []; const adiv = (acont.length ? acont[0] : this.props.A.ContentDiv!); @@ -81,6 +81,7 @@ export class CollectionFreeFormLinkView extends React.Component + return !a.width || !b.width || ((!this.props.LinkDocs.length || !this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<> {text !== "-ungrouped-" ? text : ""} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index d12f93f15..702b02a20 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -31,14 +31,14 @@ export class CollectionFreeFormLinksView extends React.Component { }, [] as { a: DocumentView, b: DocumentView, l: Doc[] }[]); return connections.filter(c => c.a.props.layoutKey && c.b.props.layoutKey && c.a.props.Document.type === DocumentType.LINK && - c.a.props.bringToFront !== emptyFunction && c.b.props.bringToFront !== emptyFunction // this prevents links to be drawn to anchors in CollectionTree views -- this is a hack that should be fixed + c.a.props.bringToFront !== emptyFunction && c.b.props.bringToFront !== emptyFunction // bcz: this prevents links to be drawn to anchors in CollectionTree views -- this is a hack that should be fixed ).map(c => ); } render() { return
    - {SelectionManager.GetIsDragging() ? (null) : this.uniqueConnections} + {this.uniqueConnections} {this.props.children}
    ; diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 3b1ced815..8e3c15908 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -40,7 +40,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent { - setupMoveUpEvents(this, e, this.onPointerMove, () => { }, this.onClick); + setupMoveUpEvents(this, e, this.onPointerMove, () => { }, this.onClick, false); } onPointerMove = action((e: PointerEvent, down: number[], delta: number[]) => { const cdiv = this._ref && this._ref.current && this._ref.current.parentElement; @@ -107,6 +107,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent this.openLinkTargetOnRight(e), icon: "eye" }); funcs.push({ description: "Open Link on Right", event: () => this.openLinkDocOnRight(e), icon: "eye" }); funcs.push({ description: "Open Link Editor", event: () => 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" }); } -- cgit v1.2.3-70-g09d2 From da2be3c1d53584cb4b0ea2920a20fd524dcba89d Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 22 Apr 2020 18:03:49 -0400 Subject: made hyperlink lines curved --- .../collectionFreeForm/CollectionFreeFormLinkView.scss | 1 + .../collectionFreeForm/CollectionFreeFormLinkView.tsx | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'src/client') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss index 75af11537..05111adb4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss @@ -4,6 +4,7 @@ pointer-events: all; stroke-width: 3px; transition: opacity 0.5s ease-in; + fill: transparent; } .collectionfreeformlinkview-linkCircle { stroke: rgb(0,0,0); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index b2ea7290d..cf12ef382 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -94,6 +94,13 @@ export class CollectionFreeFormLinkView extends React.Component {text !== "-ungrouped-" ? text : ""} - + {/* + x2={`${pt2[0]}`} y2={`${pt2[1]}`} /> */} ); } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 59ad91093d019cf31dd7b602b9ac2ffc3f9699b2 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 22 Apr 2020 18:44:01 -0400 Subject: some more menu simplification. fix placement of link anchor in text collection --- src/client/views/nodes/DocumentView.scss | 4 ++++ src/client/views/nodes/DocumentView.tsx | 14 ++++++-------- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) (limited to 'src/client') diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 692493414..c9a745809 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -37,6 +37,10 @@ .documentView-linkAnchorBoxAnchor { display:flex; overflow: hidden; + + .documentView-node { + width:10px !important; + } } .documentView-lock { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d8783c458..d789a9ce2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -721,19 +721,15 @@ export class DocumentView extends DocComponent(Docu 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" }); - layoutItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); + + const existing = cm.findByDescription("Options..."); + const layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : []; layoutItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); layoutItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); - layoutItems.push({ description: !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" }); layoutItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); layoutItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" }); - layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); - layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); - !existing && cm.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" }); + !existing && cm.addItem({ description: "Options...", subitems: layoutItems, icon: "compass" }); const open = cm.findByDescription("Open New Perspective..."); const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; @@ -763,6 +759,8 @@ export class DocumentView extends DocComponent(Docu const more = cm.findByDescription("More..."); const moreItems: ContextMenuProps[] = more && "subitems" in more ? more.subitems : []; + moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); + moreItems.push({ description: !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" }); if (!ClientUtils.RELEASE) { // let copies: ContextMenuProps[] = []; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index c8eb4c23c..2c89d53d8 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -422,7 +422,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, icon: "expand-arrows-alt" })); - ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } recordDictation = () => { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 6bc7c8440..cf6a7ba5b 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -180,7 +180,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent Date: Wed, 22 Apr 2020 20:29:48 -0400 Subject: switched close button to be iconify, and iconfiy to be maximize --- src/client/views/DocumentDecorations.tsx | 36 +++++++++++----------- src/client/views/nodes/DocumentView.tsx | 1 - src/client/views/nodes/LabelBox.tsx | 2 +- .../authentication/models/current_user_utils.ts | 19 +++++++++--- 4 files changed, 34 insertions(+), 24 deletions(-) (limited to 'src/client') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 5d6242201..43c7751fa 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -19,6 +19,7 @@ import { DocumentView } from "./nodes/DocumentView"; import React = require("react"); import { Id } from '../../new_fields/FieldSymbols'; import e = require('express'); +import { CollectionDockingView } from './collections/CollectionDockingView'; library.add(faCaretUp); library.add(faObjectGroup); @@ -36,8 +37,6 @@ library.add(faCloudUploadAlt); library.add(faSyncAlt); library.add(faShare); -export type CloseCall = (toBeDeleted: DocumentView[]) => void; - @observer export class DocumentDecorations extends React.Component<{}, { value: string }> { static Instance: DocumentDecorations; @@ -51,7 +50,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @observable private _titleControlString: string = "#title"; @observable private _edtingTitle = false; @observable private _hidden = false; - @observable private _addedCloseCalls: CloseCall[] = []; @observable public Interacting = false; @observable public pushIcon: IconProp = "arrow-alt-circle-up"; @@ -91,14 +89,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); } - addCloseCall = (handler: CloseCall) => { - const currentOffset = this._addedCloseCalls.length - 1; - this._addedCloseCalls.push((toBeDeleted: DocumentView[]) => { - this._addedCloseCalls.splice(currentOffset, 1); - handler(toBeDeleted); - }); - } - titleBlur = action((commit: boolean) => { this._edtingTitle = false; if (commit) { @@ -171,7 +161,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } onCloseDown = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onCloseClick); + setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onMinimizeClick); } @undoBatch @action @@ -180,7 +170,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> 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); @@ -189,8 +178,19 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } } @action - onMinimizeDown = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onMinimizeClick); + onMaximizeDown = (e: React.PointerEvent): void => { + setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onMaximizeClick); + } + @undoBatch + @action + onMaximizeClick = (e: PointerEvent): void => { + if (e.button === 0) { + const selectedDocs = SelectionManager.SelectedDocuments(); + if (selectedDocs.length) { + CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0], selectedDocs[0].props.LibraryPath) + } + } + SelectionManager.DeselectAll(); } @undoBatch @action @@ -398,11 +398,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> return (null); } const minimal = bounds.r - bounds.x < 100 ? true : false; - const minimizeIcon = minimal ? ( + const maximizeIcon = minimal ? (
    ) : ( -
    +
    {/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/} {SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
    ); @@ -457,7 +457,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> left: bounds.x - this._resizeBorderWidth / 2, top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight, }}> - {minimizeIcon} + {maximizeIcon} {titleArea}
    diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d789a9ce2..a19ba6506 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -733,7 +733,6 @@ export class DocumentView extends DocComponent(Docu const open = cm.findByDescription("Open New Perspective..."); const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; - openItems.push({ description: "Open Full Screen", event: () => CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(this, this.props.LibraryPath), icon: "desktop" }); openItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); templateDoc && openItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" }); !open && cm.addItem({ description: "Open New Perspective...", subitems: openItems, icon: "external-link-alt" }); diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 391e359cc..5c2fc3ffe 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -77,7 +77,7 @@ export class LabelBox extends ViewBoxBaseComponent
    - {StrCast(this.layoutDoc.text, StrCast(this.layoutDoc.title))} + {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 6c411f10b..82efe5d4e 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -3,7 +3,7 @@ import * as rp from 'request-promise'; import { DocServer } from "../../../client/DocServer"; import { Docs, DocumentOptions } from "../../../client/documents/Documents"; import { UndoManager } from "../../../client/util/UndoManager"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; +import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { ScriptField, ComputedField } from "../../../new_fields/ScriptField"; @@ -147,8 +147,16 @@ export class CurrentUserUtils { iconView.isTemplateDoc = makeTemplate(iconView); 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)") }); + iconRtfView.isTemplateDoc = makeTemplate(iconRtfView, true, "icon_" + DocumentType.RTF); + doc["template-icon-view-rtf"] = new PrefetchProxy(iconRtfView); + } 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)") }); + 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["template-icon-view-img"] = new PrefetchProxy(iconImageView); } @@ -158,9 +166,12 @@ export class CurrentUserUtils { doc["template-icon-view-col"] = new PrefetchProxy(iconColView); } 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 })); + 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, doc["template-icon-view-rtf"] as Doc], { title: "icon templates", _height: 75 })); } else { - DocListCast(Cast(doc["template-icons"], Doc, null)?.data); // prefetch templates + const templateIconsDoc = Cast(doc["template-icons"], Doc, null); + DocListCastAsync(templateIconsDoc).then(list => templateIconsDoc.data = new List([doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, + doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc])); } return doc["template-icons"] as Doc; } -- 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') 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: Thu, 23 Apr 2020 02:09:10 -0400 Subject: fixed performance of panning with something selected by making TemplateMenu ot render unless it has explicitly been activated. --- src/client/views/DocumentButtonBar.tsx | 62 ++++++---------------- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/TemplateMenu.tsx | 9 ++-- src/client/views/Templates.tsx | 45 ++-------------- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 8 +-- src/client/views/nodes/FormattedTextBox.tsx | 6 +-- src/client/views/webcam/DashWebRTCVideo.tsx | 2 +- 9 files changed, 37 insertions(+), 101 deletions(-) (limited to 'src/client') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 93987b751..5936bbfb8 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -6,7 +6,7 @@ import { observer } from "mobx-react"; import { Doc, DocListCast } from "../../new_fields/Doc"; import { RichTextField } from '../../new_fields/RichTextField'; import { NumCast, StrCast } from "../../new_fields/Types"; -import { emptyFunction } from "../../Utils"; +import { emptyFunction, setupMoveUpEvents } from "../../Utils"; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; import { UndoManager } from "../util/UndoManager"; import { CollectionDockingView, DockedFrameRenderer } from './collections/CollectionDockingView'; @@ -108,10 +108,8 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | get view0() { return this.props.views?.[0]; } @action - onLinkButtonMoved = (e: PointerEvent): void => { - if (this._linkButton.current !== null && (Math.abs(e.clientX - this._downX) > 3 || Math.abs(e.clientY - this._downY) > 3)) { - document.removeEventListener("pointermove", this.onLinkButtonMoved); - document.removeEventListener("pointerup", this.onLinkButtonUp); + onLinkButtonMoved = (e: PointerEvent) => { + if (this._linkButton.current !== null) { const linkDrag = UndoManager.StartBatch("Drag Link"); this.view0 && DragManager.StartLinkDrag(this._linkButton.current, this.view0.props.Document, e.pageX, e.pageY, { dragComplete: dropEv => { @@ -131,26 +129,16 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | }, hideSource: false }); + return true; } - e.stopPropagation(); + return false; } onLinkButtonDown = (e: React.PointerEvent): void => { - this._downX = e.clientX; - this._downY = e.clientY; - document.removeEventListener("pointermove", this.onLinkButtonMoved); - document.addEventListener("pointermove", this.onLinkButtonMoved); - document.removeEventListener("pointerup", this.onLinkButtonUp); - document.addEventListener("pointerup", this.onLinkButtonUp); - e.stopPropagation(); + setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, emptyFunction); } - onLinkButtonUp = (e: PointerEvent): void => { - document.removeEventListener("pointermove", this.onLinkButtonMoved); - document.removeEventListener("pointerup", this.onLinkButtonUp); - e.stopPropagation(); - } @computed get considerGoogleDocsPush() { @@ -257,29 +245,12 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | }} />; } - private _downx = 0; - private _downy = 0; - onAliasButtonUp = (e: PointerEvent): void => { - document.removeEventListener("pointermove", this.onAliasButtonMoved); - document.removeEventListener("pointerup", this.onAliasButtonUp); - e.stopPropagation(); - } - + @observable _aliasDown = false; onAliasButtonDown = (e: React.PointerEvent): void => { - this._downx = e.clientX; - this._downy = e.clientY; - e.stopPropagation(); - e.preventDefault(); - document.removeEventListener("pointermove", this.onAliasButtonMoved); - document.addEventListener("pointermove", this.onAliasButtonMoved); - document.removeEventListener("pointerup", this.onAliasButtonUp); - document.addEventListener("pointerup", this.onAliasButtonUp); - } - onAliasButtonMoved = (e: PointerEvent): void => { - if (this._dragRef.current !== null && (Math.abs(e.clientX - this._downx) > 4 || Math.abs(e.clientY - this._downy) > 4)) { - document.removeEventListener("pointermove", this.onAliasButtonMoved); - document.removeEventListener("pointerup", this.onAliasButtonUp); - + setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction); + }; + onAliasButtonMoved = () => { + if (this._dragRef.current) { const dragDocView = this.props.views[0]!; const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]); const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); @@ -290,9 +261,10 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | offsetY: dragData.offset[1], hideSource: false }); + return true; } - e.stopPropagation(); - } + return false; + }; @computed get templateButton() { @@ -301,9 +273,9 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | Array.from(Object.values(Templates.TemplateList)).map(template => templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean))); return !view0 ? (null) :
    - v).map(v => v as DocumentView)} templates={templates} />}> -
    + this._aliasDown = true)} onClose={action(() => this._aliasDown = false)} + content={!this._aliasDown ? (null) : v).map(v => v as DocumentView)} templates={templates} />}> +
    {}
    diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 6e699bc68..e1348a317 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -191,7 +191,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (e.button === 0) { const selectedDocs = SelectionManager.SelectedDocuments(); if (selectedDocs.length) { - CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0], selectedDocs[0].props.LibraryPath) + CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0], selectedDocs[0].props.LibraryPath); } } SelectionManager.DeselectAll(); diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index b76137f06..6894500dd 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -124,7 +124,7 @@ export class TemplateMenu extends React.Component { templateMenu.push(); templateMenu.push(); if (noteTypesDoc) { - addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction(`templateIsUsed(self)`)); + addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction(`templateIsUsed(self,firstDoc)`, {}, { firstDoc })); this._addedKeys && Array.from(this._addedKeys).filter(key => !noteTypes.some(nt => nt.title === key)).forEach(template => templateMenu.push( this.toggleLayout(e, template)} />)); } @@ -175,11 +175,10 @@ Scripting.addGlobal(function switchView(doc: Doc, template: Doc | undefined) { return templateTitle && DocumentView.makeCustomViewClicked(doc, Docs.Create.FreeformDocument, templateTitle, template); }); -Scripting.addGlobal(function templateIsUsed(templateDoc: Doc) { - const firstDoc = SelectionManager.SelectedDocuments().length ? SelectionManager.SelectedDocuments()[0].props.Document : undefined; - if (firstDoc) { +Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, selDoc: Doc) { + if (selDoc) { const template = StrCast(templateDoc.dragFactory ? Cast(templateDoc.dragFactory, Doc, null)?.title : templateDoc.title); - return StrCast(firstDoc.layoutKey) === "layout_" + template ? 'check' : 'unchecked'; + return StrCast(selDoc.layoutKey) === "layout_" + template ? 'check' : 'unchecked'; } return false; }); \ No newline at end of file diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 8c60f1c36..a6dbaa650 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -1,45 +1,23 @@ -import React = require("react"); - -export enum TemplatePosition { - InnerTop, - InnerBottom, - InnerRight, - InnerLeft, - TopRight, - OutterTop, - OutterBottom, - OutterRight, - OutterLeft, -} - export class Template { - constructor(name: string, position: TemplatePosition, layout: string) { + constructor(name: string, layout: string) { this._name = name; - this._position = position; this._layout = layout; } private _name: string; - private _position: TemplatePosition; private _layout: string; get Name(): string { return this._name; } - get Position(): TemplatePosition { - return this._position; - } - get Layout(): string { return this._layout; } } export namespace Templates { - // export const BasicLayout = new Template("Basic layout", "{layout}"); - - export const Caption = new Template("Caption", TemplatePosition.OutterBottom, + export const Caption = new Template("Caption", `
    {layout}
    @@ -47,16 +25,7 @@ export namespace Templates {
    ` ); - export const Title = new Template("Title", TemplatePosition.InnerTop, - `
    -
    - {props.Document.title} -
    -
    -
    {layout}
    -
    -
    ` ); - export const TitleHover = new Template("TitleHover", TemplatePosition.InnerTop, + export const Title = new Template("Title", `
    {props.Document.title} @@ -65,14 +34,8 @@ export namespace Templates {
    {layout}
    ` ); + export const TitleHover = new Template("TitleHover", Title.Layout); export const TemplateList: Template[] = [Title, TitleHover, Caption]; - - export function sortTemplates(a: Template, b: Template) { - if (a.Position < b.Position) { return -1; } - if (a.Position > b.Position) { return 1; } - return 0; - } - } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 55e55e56c..8ead1c300 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1057,7 +1057,7 @@ export class CollectionFreeFormView extends CollectionSubView 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" }); - optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" }); + optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = (this.props.Document.jitterRotation ? 0 : 10)), icon: "paint-brush" }); optionItems.push({ description: "Import document", icon: "upload", event: ({ x, y }) => { const input = document.createElement("input"); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 615b05e43..4b282b0c9 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -31,7 +31,7 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu if ((this.props.Document.onDragStart || (this.props.Document.rootDocument)) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTEmplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template } else { - DocumentView._focusHack = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY) || [0, 0]; - DocumentView._focusHack = [DocumentView._focusHack[0] + NumCast(this.props.Document.x), DocumentView._focusHack[1] + NumCast(this.props.Document.y)]; + if (this.props.Document.type === DocumentType.RTF) { + DocumentView._focusHack = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY) || [0, 0]; + DocumentView._focusHack = [DocumentView._focusHack[0] + NumCast(this.props.Document.x), DocumentView._focusHack[1] + NumCast(this.props.Document.y)]; - this.props.focus(this.props.Document, false); + this.props.focus(this.props.Document, false); + } SelectionManager.SelectDoc(this, e.ctrlKey); } preventDefault = false; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 1329f7dcf..fd7462a10 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -441,9 +441,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp 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" }) + 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..."); @@ -455,7 +455,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp 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" }); } diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index 1d52ba38f..2ea011316 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -3,7 +3,7 @@ import React = require("react"); import { CollectionFreeFormDocumentViewProps } from "../nodes/CollectionFreeFormDocumentView"; import { FieldViewProps, FieldView } from "../nodes/FieldView"; import { observable, action } from "mobx"; -import { DocumentDecorations, CloseCall } from "../DocumentDecorations"; +import { DocumentDecorations } from "../DocumentDecorations"; import { InkingControl } from "../InkingControl"; import "../../views/nodes/WebBox.scss"; import "./DashWebRTCVideo.scss"; -- cgit v1.2.3-70-g09d2 From d2682eba642d2f10e94822d9c9864a6477052e06 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 23 Apr 2020 02:09:38 -0400 Subject: lint errors --- src/client/views/DocumentButtonBar.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 5936bbfb8..c02f79187 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -248,7 +248,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | @observable _aliasDown = false; onAliasButtonDown = (e: React.PointerEvent): void => { setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction); - }; + } onAliasButtonMoved = () => { if (this._dragRef.current) { const dragDocView = this.props.views[0]!; @@ -264,7 +264,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | return true; } return false; - }; + } @computed get templateButton() { -- cgit v1.2.3-70-g09d2 From 8a8f2c8848fe76e26188666790accaf236267e78 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 23 Apr 2020 13:11:51 -0400 Subject: fixed color box interactions. added starburst layout engine. --- src/client/views/DocComponent.tsx | 6 ++-- src/client/views/DocumentDecorations.tsx | 4 ++- .../CollectionFreeFormLayoutEngines.tsx | 28 ++++++++++++++- .../collectionFreeForm/CollectionFreeFormView.tsx | 42 +++++++++++++++------- src/client/views/nodes/ColorBox.tsx | 2 +- 5 files changed, 64 insertions(+), 18 deletions(-) (limited to 'src/client') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index f19f9308a..0a8f0c9a7 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -1,7 +1,7 @@ import { Doc, Opt, DataSym } from '../../new_fields/Doc'; import { Touchable } from './Touchable'; import { computed, action, observable } from 'mobx'; -import { Cast } from '../../new_fields/Types'; +import { Cast, BoolCast } from '../../new_fields/Types'; import { listSpec } from '../../new_fields/Schema'; import { InkingControl } from './InkingControl'; import { InkTool } from '../../new_fields/InkField'; @@ -53,7 +53,7 @@ export function ViewBoxBaseComponent

    (schemaCtor: // key where data is stored @computed get fieldKey() { return this.props.fieldKey; } - active = (outsideReaction?: boolean) => !this.props.Document.isBackground && (this.props.rootSelected(outsideReaction) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools + active = (outsideReaction?: boolean) => !this.props.Document.isBackground && (this.props.rootSelected(outsideReaction) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0 || this.layoutDoc.forceActive);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; } return Component; @@ -114,7 +114,7 @@ export function ViewBoxAnnotatableComponent

    this.props.whenActiveChanged(this._isChildActive = isActive)); active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.props.Document.isBackground) && - (this.props.rootSelected(outsideReaction) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) + (this.props.rootSelected(outsideReaction) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0 || BoolCast((this.layoutDoc as any).forceActive)) ? true : false) annotationsActive = (outsideReaction?: boolean) => (InkingControl.Instance.selectedTool !== InkTool.None || (this.props.Document.isBackground && this.props.active()) || (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index e1348a317..a4ebde3b3 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -136,6 +136,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let child = SelectionManager.SelectedDocuments()[0].ContentDiv!.children[0]; while (child.children.length) { const next = Array.from(child.children).find(c => !c.className.includes("collectionViewChrome")); + if (next?.className.includes("documentView-node")) break; if (next) child = next; else break; } @@ -191,7 +192,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (e.button === 0) { const selectedDocs = SelectionManager.SelectedDocuments(); if (selectedDocs.length) { - CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0], selectedDocs[0].props.LibraryPath); + //CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0], selectedDocs[0].props.LibraryPath); + CollectionDockingView.AddRightSplit(selectedDocs[0].props.Document, selectedDocs[0].props.LibraryPath); } } SelectionManager.DeselectAll(); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index bd4db89ec..0a5ea3baf 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -1,4 +1,4 @@ -import { Doc, Field, FieldResult } from "../../../../new_fields/Doc"; +import { Doc, Field, FieldResult, WidthSym, HeightSym } from "../../../../new_fields/Doc"; import { NumCast, StrCast, Cast } from "../../../../new_fields/Types"; import { ScriptBox } from "../../ScriptBox"; import { CompileScript } from "../../../util/Scripting"; @@ -76,6 +76,32 @@ interface PivotColumn { } +export function computerStarburstLayout( + poolData: Map, + pivotDoc: Doc, + childDocs: Doc[], + filterDocs: Doc[], + childPairs: { layout: Doc, data?: Doc }[], + panelDim: number[], + viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] +) { + const docMap = new Map(); + const burstDim = [NumCast(pivotDoc.starburstRadius, panelDim[0]), NumCast(pivotDoc.starburstRadius, panelDim[1])] + childDocs.forEach((doc, i) => { + 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), + width: doc[WidthSym](), + height: doc[HeightSym](), + payload: undefined + }); + }); + return normalizeResults(burstDim, 12, childPairs, docMap, poolData, viewDefsToJSX, [], 0, [], childDocs.filter(c => !filterDocs.includes(c))); +} + + export function computePivotLayout( poolData: Map, pivotDoc: Doc, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8ead1c300..5967f36f9 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -37,7 +37,7 @@ import { pageSchema } from "../../nodes/ImageBox"; import PDFMenu from "../../pdf/PDFMenu"; import { CollectionDockingView } from "../CollectionDockingView"; import { CollectionSubView } from "../CollectionSubView"; -import { computePivotLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines"; +import { computePivotLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult, computerStarburstLayout } from "./CollectionFreeFormLayoutEngines"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; @@ -941,13 +941,16 @@ export class CollectionFreeFormView extends CollectionSubView) { - return computeTimelineLayout(poolData, this.props.Document, this.childDocs, this.childDocs, - this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX); - } - - doPivotLayout(poolData: Map) { - return computePivotLayout(poolData, this.props.Document, this.childDocs, this.childDocs, + doEngineLayout(poolData: Map, + engine: ( + poolData: Map, + pivotDoc: Doc, + childDocs: Doc[], + filterDocs: Doc[], + childPairs: { layout: Doc, data?: Doc }[], + panelDim: number[], + viewDefsToJSX: ((views: ViewDefBounds[]) => ViewDefResult[])) => ViewDefResult[]) { + return engine(poolData, this.props.Document, this.childDocs, this.childDocs, this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX); } @@ -966,9 +969,12 @@ export class CollectionFreeFormView extends CollectionSubView(); - switch (this.props.layoutEngine?.()) { - case "timeline": return { newPool, computedElementData: this.doTimelineLayout(newPool) }; - case "pivot": return { newPool, computedElementData: this.doPivotLayout(newPool) }; + const engine = StrCast(this.layoutDoc._layoutEngine) || this.props.layoutEngine?.(); + switch (engine) { + case "pass": break; + case "timeline": return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) }; + case "pivot": return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) }; + case "starburst": return { newPool, computedElementData: this.doEngineLayout(newPool, computerStarburstLayout) }; } return { newPool, computedElementData: this.doFreeformLayout(newPool) }; } @@ -994,7 +1000,7 @@ export class CollectionFreeFormView extends CollectionSubView { + if (this.layoutDoc._layoutEngine === undefined) { + this.layoutDoc._layoutEngine = "starburst"; + this.layoutDoc.overflow = "visible"; + } else { + + this.layoutDoc._layoutEngine = "pass"; + this.layoutDoc.overflow = "hidden"; + } + + }); layoutDocsInGrid = () => { UndoManager.RunInBatch(() => { const docs = this.childLayoutPairs; @@ -1055,6 +1072,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" }); 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/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index 877dfec2d..6e4341b27 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -22,7 +22,7 @@ export class ColorBox extends ViewBoxBaseComponent e.button === 0 && !e.ctrlKey && e.stopPropagation()} - style={{ transformOrigin: "top left", transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} > + style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} > Date: Thu, 23 Apr 2020 20:52:09 -0400 Subject: fixed loading of notes with template types. changed noteTypes to ["template-notes"]. Added pass through free form layout engine. --- src/client/documents/Documents.ts | 2 +- src/client/views/DocumentDecorations.scss | 2 - src/client/views/DocumentDecorations.tsx | 14 ++--- src/client/views/TemplateMenu.tsx | 11 ++-- .../CollectionFreeFormLayoutEngines.tsx | 22 ++++++++ .../collectionFreeForm/CollectionFreeFormView.scss | 2 + .../collectionFreeForm/CollectionFreeFormView.tsx | 30 ++++++----- .../collections/collectionFreeForm/MarqueeView.tsx | 25 ++++++++- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 7 ++- src/client/views/nodes/WebBox.tsx | 3 +- src/new_fields/Doc.ts | 18 ++++++- .../authentication/models/current_user_utils.ts | 59 ++++++++++++++-------- 13 files changed, 140 insertions(+), 57 deletions(-) (limited to 'src/client') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 5ff8f29ec..578d337d6 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -973,7 +973,7 @@ export namespace DocUtils { export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number): void { ContextMenu.Instance.addItem({ description: "Add Note ...", - subitems: DocListCast((Doc.UserDoc().noteTypes as Doc).data).map((note, i) => ({ + subitems: DocListCast((Doc.UserDoc()["template-notes"] as Doc).data).map((note, i) => ({ description: ":" + StrCast(note.title), event: (args: { x: number, y: number }) => { const textDoc = Docs.Create.TextDocument("", { diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 353520026..28cf9fd47 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -143,7 +143,6 @@ $linkGap : 3px; pointer-events: all; text-align: center; cursor: pointer; - padding-right: 10px; } .documentDecorations-minimizeButton { @@ -157,7 +156,6 @@ $linkGap : 3px; position: absolute; left: 0px; top: 0px; - padding-top: 5px; width: $MINIMIZED_ICON_SIZE; height: $MINIMIZED_ICON_SIZE; max-height: 20px; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index a4ebde3b3..e4ceb75bd 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -165,8 +165,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> return true; } - onCloseDown = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onMinimizeClick); + onIconifyDown = (e: React.PointerEvent): void => { + setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onIconifyClick); } @undoBatch @action @@ -200,7 +200,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } @undoBatch @action - onMinimizeClick = (e: PointerEvent): void => { + onIconifyClick = (e: PointerEvent): void => { if (e.button === 0) { const selectedDocs = SelectionManager.SelectedDocuments().map(sd => sd); selectedDocs.map(dv => { @@ -408,9 +408,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>

    ) : ( -
    +
    {/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/} - {SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."} +
    ); const titleArea = this._edtingTitle ? @@ -465,8 +465,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> }}> {maximizeIcon} {titleArea} -
    - +
    + {SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
    e.preventDefault()}>
    diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 6894500dd..e3c749a4d 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -112,8 +112,7 @@ export class TemplateMenu extends React.Component { render() { const firstDoc = this.props.docViews[0].props.Document; const templateName = StrCast(firstDoc.layoutKey, "layout").replace("layout_", ""); - const noteTypesDoc = Cast(Doc.UserDoc().noteTypes, Doc, null); - const noteTypes = DocListCast(noteTypesDoc?.data); + const noteTypes = DocListCast(Cast(Doc.UserDoc()["template-notes"], Doc, null)); const addedTypes = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data); const layout = Doc.Layout(firstDoc); const templateMenu: Array = []; @@ -123,11 +122,9 @@ export class TemplateMenu extends React.Component { templateMenu.push(); templateMenu.push(); templateMenu.push(); - if (noteTypesDoc) { - addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction(`templateIsUsed(self,firstDoc)`, {}, { firstDoc })); - this._addedKeys && Array.from(this._addedKeys).filter(key => !noteTypes.some(nt => nt.title === key)).forEach(template => templateMenu.push( - this.toggleLayout(e, template)} />)); - } + addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction(`templateIsUsed(self,firstDoc)`, {}, { firstDoc })); + this._addedKeys && Array.from(this._addedKeys).filter(key => !noteTypes.some(nt => nt.title === key)).forEach(template => templateMenu.push( + this.toggleLayout(e, template)} />)); return
      {templateMenu} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 0a5ea3baf..1ec0542a3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -75,6 +75,28 @@ interface PivotColumn { filters: string[]; } +export function computerPassLayout( + poolData: Map, + pivotDoc: Doc, + childDocs: Doc[], + filterDocs: Doc[], + childPairs: { layout: Doc, data?: Doc }[], + panelDim: number[], + viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] +) { + const docMap = new Map(); + childDocs.forEach((doc, i) => { + docMap.set(doc, { + type: "doc", + x: NumCast(doc.x), + y: NumCast(doc.y), + width: doc[WidthSym](), + height: doc[HeightSym](), + payload: undefined + }); + }); + return normalizeResults(panelDim, 12, childPairs, docMap, poolData, viewDefsToJSX, [], 0, [], childDocs.filter(c => !filterDocs.includes(c))); +} export function computerStarburstLayout( poolData: Map, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index a00311a9c..4e4e85e13 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -9,6 +9,8 @@ height: 100%; transform-origin: left top; border-radius: inherit; + touch-action: none; + border-radius: inherit; } .collectionfreeformview-ease { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 5967f36f9..e8738b292 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -37,7 +37,7 @@ import { pageSchema } from "../../nodes/ImageBox"; import PDFMenu from "../../pdf/PDFMenu"; import { CollectionDockingView } from "../CollectionDockingView"; import { CollectionSubView } from "../CollectionSubView"; -import { computePivotLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult, computerStarburstLayout } from "./CollectionFreeFormLayoutEngines"; +import { computePivotLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult, computerStarburstLayout, computerPassLayout } from "./CollectionFreeFormLayoutEngines"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; @@ -94,6 +94,7 @@ export class CollectionFreeFormView extends CollectionSubView e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc._xPadding, 10), NumCast(this.layoutDoc._yPadding, 10)); } @@ -104,8 +105,9 @@ export class CollectionFreeFormView extends CollectionSubView this.props.Document.panTransformType === "Ease"; private panX = () => this.fitToContent ? (this.contentBounds.x + this.contentBounds.r) / 2 : this.Document._panX || 0; private panY = () => this.fitToContent ? (this.contentBounds.y + this.contentBounds.b) / 2 : this.Document._panY || 0; - private zoomScaling = () => (1 / this.parentScaling) * (this.fitToContent ? - Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y), this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)) : + private zoomScaling = () => (this.fitToContentScaling / this.parentScaling) * (this.fitToContent ? + Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y), + this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)) : this.Document.scale || 1) private centeringShiftX = () => !this.nativeWidth && !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling : 0; // shift so pan position is at center of window for non-overlay collections @@ -971,7 +973,7 @@ export class CollectionFreeFormView extends CollectionSubView(); const engine = StrCast(this.layoutDoc._layoutEngine) || this.props.layoutEngine?.(); switch (engine) { - case "pass": break; + case "pass": return { newPool, computedElementData: this.doEngineLayout(newPool, computerPassLayout) } case "timeline": return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) }; case "pivot": return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) }; case "starburst": return { newPool, computedElementData: this.doEngineLayout(newPool, computerStarburstLayout) }; @@ -993,6 +995,7 @@ export class CollectionFreeFormView extends CollectionSubView this._cachedPool.set(k, newPool.get(k))); const elements: ViewDefResult[] = computedElementData.slice(); + const engine = this.props.layoutEngine?.() || this.props.Document._layoutEngine; this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).forEach(pair => elements.push({ ele: { if (this.layoutDoc._layoutEngine === undefined) { - this.layoutDoc._layoutEngine = "starburst"; - this.layoutDoc.overflow = "visible"; + Doc.makeStarburst(this.layoutDoc); } else { - - this.layoutDoc._layoutEngine = "pass"; + this.layoutDoc._layoutEngine = undefined; this.layoutDoc.overflow = "hidden"; + this.layoutDoc._fitToBox = undefined; } - }); layoutDocsInGrid = () => { UndoManager.RunInBatch(() => { @@ -1141,7 +1142,7 @@ export class CollectionFreeFormView extends CollectionSubView - {this.children} @@ -1216,6 +1217,7 @@ interface CollectionFreeFormViewPannableContentsProps { zoomScaling: () => number; easing: () => boolean; children: () => JSX.Element[]; + shifted: boolean; } @observer @@ -1227,7 +1229,11 @@ class CollectionFreeFormViewPannableContents extends React.Component + return
      {this.props.children()}
      ; } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 454c3a5f2..2518ac629 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -20,6 +20,7 @@ import { CognitiveServices } from "../../../cognitive_services/CognitiveServices import { RichTextField } from "../../../../new_fields/RichTextField"; import { CollectionView } from "../CollectionView"; import { FormattedTextBox } from "../../nodes/FormattedTextBox"; +import { ScriptField } from "../../../../new_fields/ScriptField"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -332,6 +333,25 @@ export class MarqueeView extends React.Component { + const bounds = this.Bounds; + const selected = this.marqueeSelect(false); + selected.map(d => { + 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.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); + this.props.addDocument(newCollection); + this.props.selectDocuments([newCollection], []); + MarqueeOptionsMenu.Instance.fadeOut(true); + this.hideMarquee(); + Doc.makeStarburst(newCollection); + } + @action collection = (e: KeyboardEvent | React.PointerEvent | undefined) => { const bounds = this.Bounds; @@ -476,7 +496,7 @@ export class MarqueeView extends React.Component(Docu 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().noteTypes, 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 diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index fd7462a10..6ed2a1b9e 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -405,7 +405,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp !this.props.Document.rootDocument && funcs.push({ description: "Make Template", event: () => { this.props.Document.isTemplateDoc = makeTemplate(this.props.Document, true); - Doc.AddDocToList(Cast(Doc.UserDoc().noteTypes, Doc, null), "data", this.props.Document); + Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.props.Document); }, icon: "eye" }); funcs.push({ description: "Toggle Single Line", event: () => this.props.Document._singleLine = !this.props.Document._singleLine, icon: "expand-arrows-alt" }); @@ -433,9 +433,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp 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 => { + const noteTypesDoc = Cast(Doc.UserDoc()["template-notes"], Doc, null); + DocListCast(noteTypesDoc?.data).forEach(note => { changeItems.push({ description: StrCast(note.title), event: () => { Doc.setNativeView(this.props.Document); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 66ddf64c9..4e383e468 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -317,7 +317,8 @@ export class WebBox extends ViewBoxAnnotatableComponent; } else if (field instanceof WebField) { - view =