From 5931380effc04d63bb05c47eb6bde7b20a1b214f Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 16 Nov 2023 16:18:32 -0500 Subject: removed touch code that wasn't being used or maintained --- src/client/views/nodes/ScriptingBox.tsx | 1 - 1 file changed, 1 deletion(-) (limited to 'src/client/views/nodes/ScriptingBox.tsx') diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 7c8a1849e..197c520c7 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -27,7 +27,6 @@ const _global = (window /* browser */ || global) /* node */ as any; @observer export class ScriptingBox extends ViewBoxAnnotatableComponent() { private dropDisposer?: DragManager.DragDropDisposer; - protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined; public static LayoutString(fieldStr: string) { return FieldView.LayoutString(ScriptingBox, fieldStr); } -- cgit v1.2.3-70-g09d2 From ba3b3f6f261074bd3f35012bde8730f5d4a36905 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 29 Nov 2023 10:02:34 -0500 Subject: numerous changes to fix bugs and to fix/remove old or hacky code. fixed doc dec resizing. moving this.rootDoc => this.Document . fixing template artifacts. --- src/client/documents/Documents.ts | 19 +- src/client/util/CurrentUserUtils.ts | 96 +-- src/client/util/Scripting.ts | 4 +- src/client/views/DashboardView.tsx | 2 +- src/client/views/DocComponent.tsx | 16 +- src/client/views/DocumentButtonBar.tsx | 14 +- src/client/views/DocumentDecorations.tsx | 18 +- src/client/views/GlobalKeyHandler.ts | 4 +- src/client/views/MainView.tsx | 6 +- src/client/views/MarqueeAnnotator.tsx | 26 +- src/client/views/PropertiesButtons.tsx | 5 +- src/client/views/PropertiesView.tsx | 47 +- src/client/views/StyleProvider.tsx | 9 +- .../views/collections/CollectionDockingView.tsx | 53 +- src/client/views/collections/CollectionMenu.tsx | 824 +-------------------- .../views/collections/CollectionNoteTakingView.tsx | 4 +- .../views/collections/CollectionPileView.tsx | 16 +- .../collections/CollectionStackedTimeline.tsx | 16 +- .../views/collections/CollectionStackingView.scss | 2 +- .../views/collections/CollectionStackingView.tsx | 96 ++- src/client/views/collections/CollectionSubView.tsx | 20 +- .../views/collections/CollectionTimeView.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 16 +- src/client/views/collections/TabDocView.tsx | 4 +- src/client/views/collections/TreeView.tsx | 13 +- .../CollectionFreeFormLayoutEngines.tsx | 1 + .../CollectionFreeFormPannableContents.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 199 ++--- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../collectionGrid/CollectionGridView.tsx | 5 +- .../collectionLinear/CollectionLinearView.tsx | 8 +- .../CollectionMulticolumnView.scss | 2 +- .../CollectionMulticolumnView.tsx | 39 +- .../CollectionMultirowView.scss | 5 - .../CollectionMultirowView.tsx | 37 +- .../collectionSchema/CollectionSchemaView.tsx | 10 +- .../collectionSchema/SchemaTableCell.tsx | 3 +- src/client/views/global/globalScripts.ts | 8 +- src/client/views/nodes/AudioBox.tsx | 4 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 51 +- src/client/views/nodes/DocumentContentsView.tsx | 23 +- src/client/views/nodes/DocumentView.tsx | 171 +++-- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 121 ++- src/client/views/nodes/FunctionPlotBox.tsx | 6 +- src/client/views/nodes/ImageBox.tsx | 3 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/LinkBox.tsx | 18 +- src/client/views/nodes/MapBox/MapPushpinBox.tsx | 6 +- src/client/views/nodes/PDFBox.tsx | 1 - .../views/nodes/RecordingBox/RecordingBox.tsx | 12 +- src/client/views/nodes/ScreenshotBox.tsx | 4 +- src/client/views/nodes/ScriptingBox.tsx | 6 +- src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 53 +- .../views/nodes/formattedText/RichTextMenu.tsx | 46 +- .../views/nodes/formattedText/RichTextRules.ts | 2 +- src/client/views/nodes/trails/PresBox.tsx | 97 ++- src/client/views/nodes/trails/PresElementBox.tsx | 64 +- src/client/views/pdf/PDFViewer.tsx | 5 +- src/client/views/search/SearchBox.tsx | 2 +- src/fields/Doc.ts | 15 +- src/fields/ScriptField.ts | 26 +- 63 files changed, 798 insertions(+), 1605 deletions(-) (limited to 'src/client/views/nodes/ScriptingBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 029653204..4def19384 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -292,6 +292,7 @@ export class DocumentOptions { childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox layout in tree view) childLayoutString?: string; // template string for collection to use to render its children childDocumentsActive?: BOOLt = new BoolInfo('whether child documents are active when parent is document active'); + childLayoutFitWidth?: BOOLt = new BoolInfo("whether a child doc's fitWith should be overriden by collection"); childDontRegisterViews?: BOOLt = new BoolInfo('whether child document views should be registered so that they can be found when following links, etc'); childHideLinkButton?: BOOLt = new BoolInfo('hide link buttons on all children'); childContextMenuFilters?: List; @@ -1134,7 +1135,7 @@ export namespace Docs { // } export function FreeformDocument(documents: Array, options: DocumentOptions, id?: string) { - const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20, ...options, _type_collection: CollectionViewType.Freeform }, id); + const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _type_collection: CollectionViewType.Freeform }, id); documents.forEach(d => Doc.SetContainer(d, inst)); return inst; } @@ -1217,7 +1218,7 @@ export namespace Docs { } export function FunctionPlotDocument(documents: Array, options?: DocumentOptions) { - return InstanceFromProto(Prototypes.get(DocumentType.FUNCPLOT), new List(documents), { ...(options || {}) }); + return InstanceFromProto(Prototypes.get(DocumentType.FUNCPLOT), new List(documents), { title: 'func plot', ...(options || {}) }); } export function ButtonDocument(options?: DocumentOptions) { @@ -1487,7 +1488,7 @@ export namespace DocUtils { Object.keys(scripts).map(key => { const script = scripts[key]; if (ScriptCast(doc[key])?.script.originalScript !== scripts[key] && script) { - doc[key] = ScriptField.MakeScript(script, { + (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = ScriptField.MakeScript(script, { self: Doc.name, this: Doc.name, dragData: DragManager.DocumentDragData.name, @@ -1511,7 +1512,7 @@ export namespace DocUtils { const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); if (ScriptCast(cfield)?.script.originalScript !== funcs[key]) { const setFunc = Cast(funcs[key + '-setter'], 'string', null); - doc[key] = funcs[key] ? ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, { _readOnly_: true }, setFunc) : undefined; + (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = funcs[key] ? ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, { _readOnly_: true }, setFunc) : undefined; } }); return doc; @@ -1717,7 +1718,7 @@ export namespace DocUtils { } export function createCustomView(doc: Doc, creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = 'custom', docLayoutTemplate?: Doc) { const templateName = templateSignature.replace(/\(.*\)/, ''); - docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc._isGroup && doc.transcription ? 'transcription' : doc.type), templateSignature); + docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc.isGroup && doc.transcription ? 'transcription' : doc.type), templateSignature); const customName = 'layout_' + templateSignature; const _width = NumCast(doc._width); @@ -1987,9 +1988,9 @@ ScriptingGlobals.add(function makeDelegate(proto: any) { const d = Docs.Create.DelegateDocument(proto, { title: 'child of ' + proto.title }); return d; }); -ScriptingGlobals.add(function generateLinkTitle(self: Doc) { - const link_anchor_1title = self.link_anchor_1 && self.link_anchor_1 !== self ? Cast(self.link_anchor_1, Doc, null)?.title : ''; - const link_anchor_2title = self.link_anchor_2 && self.link_anchor_2 !== self ? Cast(self.link_anchor_2, Doc, null)?.title : ''; - const relation = self.link_relationship || 'to'; +ScriptingGlobals.add(function generateLinkTitle(link: Doc) { + const link_anchor_1title = link.link_anchor_1 && link.link_anchor_1 !== link ? Cast(link.link_anchor_1, Doc, null)?.title : ''; + const link_anchor_2title = link.link_anchor_2 && link.link_anchor_2 !== link ? Cast(link.link_anchor_2, Doc, null)?.title : ''; + const relation = link.link_relationship || 'to'; return `${link_anchor_1title} (${relation}) ${link_anchor_2title}`; }); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 18c7a1fb6..2f2ac2a71 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -284,7 +284,7 @@ export class CurrentUserUtils { treeView_HasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, dropAction:'move', treeView_Type: TreeViewType.outline, backgroundColor: "white", _xMargin: 0, _yMargin: 0, _createDocOnCR: true - }, funcs: {title: 'self.text?.Text'}}, + }, funcs: {title: 'this.text?.Text'}}, ]; emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs)); @@ -339,7 +339,7 @@ export class CurrentUserUtils { /// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}, hidden?: boolean}[] { - const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target?.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())"; + const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(this.target?.data).filter(doc => !docList(this.target.viewed).includes(doc)).length.toString())"; const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails"; return [ { title: "Dashboards", toolTip: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), ignoreClick: true, icon: "desktop", funcs: {hidden: "IsNoviceMode()"} }, @@ -467,6 +467,7 @@ export class CurrentUserUtils { const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc,DocListCast(myTools?.data)?.length > 1 ? DocListCast(myTools.data)[1]:undefined); const reqdToolOps:DocumentOptions = { title: "My Tools", isSystem: true, ignoreClick: true, layout_boxShadow: "0 0", + layout_explainer: "This is a palette of documents that can be created.", _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _chromeHidden: true, }; return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdToolOps, [creatorBtns, templateBtns]); @@ -558,7 +559,7 @@ export class CurrentUserUtils { const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton, color: Colors.BLACK, buttonText: "Empty", icon: "trash", isSystem: true, toolTip: "Empty recently closed",}; - DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")}); + DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("this.target")}); if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) { recentlyClosed.contextMenuScripts = new List([ScriptField.MakeScript(clearAll("self"))!]) @@ -628,42 +629,42 @@ export class CurrentUserUtils { } static stackTools(): Button[] { return [ - { title: "Center", icon: "align-center", toolTip: "Center Align Stack", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"center", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Center", icon: "align-center", toolTip: "Center Align Stack", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"center", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform ] } static viewTools(): Button[] { return [ - { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"grid", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "View All", icon: "object-group", toolTip: "Keep all Docs in View",btnType: ButtonType.ToggleButton, ignoreClick:true, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"grid", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "View All", icon: "object-group", toolTip: "Keep all Docs in View",btnType: ButtonType.ToggleButton, ignoreClick:true, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform // want the same style as toggle button, but don't want it to act as an actual toggle, so set disableToggle to true, - { title: "Fit All", icon: "arrows-left-right", toolTip: "Fit Docs to View (once)",btnType: ButtonType.ClickButton,ignoreClick:false,expertMode: false, toolType:"fitOnce", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Cards", icon: "brain", toolTip: "Flashcards", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Arrange", icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Fit All", icon: "arrows-left-right", toolTip: "Fit Docs to View (once)",btnType: ButtonType.ClickButton,ignoreClick:false,expertMode: false, toolType:"fitOnce", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Cards", icon: "brain", toolTip: "Flashcards", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Arrange", icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform ] } static textTools():Button[] { return [ - { title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, toolType:"font", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, + { title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, toolType:"font", ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}, btnList: new List(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]) }, - { title: "Font Size",toolTip: "Font size (%size)", btnType: ButtonType.NumberDropdownButton, toolType:"fontSize", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 6 }, - { title: "Color", toolTip: "Font color (%color)", btnType: ButtonType.ColorButton, icon: "font", toolType:"fontColor",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}}, - { title: "Highlight",toolTip: "Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} }, - { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", toolType:"bold", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", toolType:"italics", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", toolType:"underline",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", toolType:"bullet", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", toolType:"decimal", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Vcenter", toolTip: "Vertical center", btnType: ButtonType.ToggleButton, icon: "pallet", toolType:"vcent", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, + { title: "Font Size",toolTip: "Font size (%size)", btnType: ButtonType.NumberDropdownButton, toolType:"fontSize", ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 6 }, + { title: "Color", toolTip: "Font color (%color)", btnType: ButtonType.ColorButton, icon: "font", toolType:"fontColor",ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}}, + { title: "Highlight",toolTip: "Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} }, + { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", toolType:"bold", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", toolType:"italics", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", toolType:"underline",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", toolType:"bullet", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", toolType:"decimal", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Vcenter", toolTip: "Vertical center", btnType: ButtonType.ToggleButton, icon: "pallet", toolType:"vcent", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, { title: "Align", toolTip: "Alignment", btnType: ButtonType.MultiToggleButton, toolType:"alignment", ignoreClick: true, subMenu: [ - { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }}, - { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, + { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}' }}, + { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, ]}, - { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}}, - { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink", expertMode:true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}}, + { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'}}, + { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink", expertMode:true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}}, // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}}, // { title: "Superscript", tooltip: "Superscript", btnType: ButtonType.ToggleButton, icon: "superscript", scripts: {onClick:: 'toggleSuperscript()'}}, // { title: "Subscript", tooltip: "Subscript", btnType: ButtonType.ToggleButton, icon: "subscript", scripts: {onClick:: 'toggleSubscript()'}}, @@ -672,15 +673,15 @@ export class CurrentUserUtils { static inkTools():Button[] { return [ - { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", toolType: "pen", scripts: {onClick:'{ return setActiveTool(self.toolType, false, _readOnly_);}' }}, - { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", toolType: "write", scripts: {onClick:'{ return setActiveTool(self.toolType, false, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }}, - { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", toolType: "eraser", scripts: {onClick:'{ return setActiveTool(self.toolType, false, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }}, - { title: "Circle", toolTip: "Circle (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "circle", toolType:GestureUtils.Gestures.Circle, scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} }, - { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", toolType:GestureUtils.Gestures.Rectangle, scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} }, - { title: "Line", toolTip: "Line (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "minus", toolType:GestureUtils.Gestures.Line, scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} }, - { title: "Mask", toolTip: "Mask", btnType: ButtonType.ToggleButton, icon: "user-circle",toolType: "inkMask", scripts: {onClick:'{ return setInkProperty(self.toolType, value, _readOnly_);}'}, funcs: {hidden:"IsNoviceMode()" } }, - { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberSliderButton, toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(self.toolType, value, _readOnly_);}'}, numBtnMin: 1}, - { title: "Ink", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", toolType: "strokeColor", ignoreClick: true, scripts: {script: '{ return setInkProperty(self.toolType, value, _readOnly_);}'} }, + { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", toolType: "pen", scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}' }}, + { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", toolType: "write", scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }}, + { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", toolType: "eraser", scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }}, + { title: "Circle", toolTip: "Circle (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "circle", toolType:GestureUtils.Gestures.Circle, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} }, + { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", toolType:GestureUtils.Gestures.Rectangle, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} }, + { title: "Line", toolTip: "Line (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "minus", toolType:GestureUtils.Gestures.Line, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} }, + { title: "Mask", toolTip: "Mask", btnType: ButtonType.ToggleButton, icon: "user-circle",toolType: "inkMask", scripts: {onClick:'{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"IsNoviceMode()" } }, + { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberSliderButton, toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, numBtnMin: 1}, + { title: "Ink", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", toolType: "strokeColor", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'} }, ]; } @@ -709,17 +710,17 @@ export class CurrentUserUtils { { title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, width: 30, scripts: { onClick: 'pinWithView(altKey)'}, funcs: {hidden: "IsNoneSelected()"}}, { title: "Header", icon: "heading", toolTip: "Doc Titlebar Color", btnType: ButtonType.ColorButton, expertMode: true, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'} }, { title: "Fill", icon: "fill-drip", toolTip: "Fill/Background Color",btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 30, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'}, funcs: {hidden: "IsNoneSelected()"}}, // Only when a document is selected - { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)'}, scripts: { onClick: '{ return toggleOverlay(_readOnly_); }'}}, // Only when floating document is selected in freeform - { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 30, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}}, - { title: "Num", icon:"", toolTip: "Frame Number (click to toggle edit mode)", btnType: ButtonType.TextButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}}, - { title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 30, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}}, - { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available - { title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected - { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Schema is selected + { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(this.toolType, this.expertMode, true)'}, scripts: { onClick: '{ return toggleOverlay(_readOnly_); }'}}, // Only when floating document is selected in freeform + { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}}, + { title: "Num", icon:"", toolTip: "Frame # (click to toggle edit mode)",btnType: ButtonType.TextButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(this.toolType, this.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}}, + { title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}}, + { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available + { title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode, true)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected + { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Schema is selected ]; } @@ -904,7 +905,7 @@ export class CurrentUserUtils { this.setupDocTemplates(doc); // sets up the template menu of templates //this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption DocUtils.AssignDocField(doc, "globalScriptDatabase", (opts) => Docs.Prototypes.MainScriptDocument(), {}); - DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents + DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, _chromeHidden:true, childLayoutFitWidth:false, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards) Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs) @@ -976,6 +977,7 @@ export class CurrentUserUtils { DashboardView.createNewDashboard(undefined, "guest dashboard"); } else { userDoc.activePage = "home"; + userDoc.noviceMode = true; } } return userDoc; diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 70c2e3842..400b63a1c 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -264,6 +264,6 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp } ScriptingGlobals.add(CompileScript); -ScriptingGlobals.add(function runScript(self: Doc, script: ScriptField) { - return script?.script.run({ this: self, self: self }).result; +ScriptingGlobals.add(function runScript(doc: Doc, script: ScriptField) { + return script?.script.run({ this: doc }).result; }); diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 9e2ed7822..2765e95e6 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -370,7 +370,7 @@ export class DashboardView extends React.Component { const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row'); - Doc.AddDocToList(Doc.MyHeaderBar, 'data', freeformDoc); + Doc.AddDocToList(Doc.MyHeaderBar, 'data', freeformDoc, undefined, undefined, true); dashboardDoc['pane-count'] = 1; freeformDoc.embedContainer = dashboardDoc; dashboardDoc.myOverlayDocs = new List(); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index fdaca8056..61b7a3bff 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -10,6 +10,8 @@ import { DocUtils } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { DocumentView } from './nodes/DocumentView'; import * as React from 'react'; +import { DocumentManager } from '../util/DocumentManager'; +import { CollectionFreeFormView } from './collections/collectionFreeForm'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) export interface DocComponentProps { @@ -26,7 +28,7 @@ export function DocComponent

() { } // This is the "The Document" -- it encapsulates, data, layout, and any templates @computed get rootDoc() { - return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; + return this.props.Document; } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info @computed get layoutDoc() { @@ -58,7 +60,9 @@ export function ViewBoxBaseComponent

() { class Component extends React.Component> { //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then //@computed get Document(): T { return schemaCtor(this.props.Document); } - + @computed get Document() { + return this.props.Document; + } // This is the "The Document" -- it encapsulates, data, layout, and any templates @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; @@ -146,7 +150,11 @@ export function ViewBoxAnnotatableComponent

() doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true); } }); - this.isAnyChildContentActive() && this.props.select(false); + if (targetDataDoc.isGroup && DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]).length < 2) { + (DocumentManager.Instance.getFirstDocumentView(targetDataDoc)?.ComponentView as CollectionFreeFormView)?.promoteCollection(); + } else { + this.isAnyChildContentActive() && this.props.select(false); + } return true; } @@ -173,7 +181,7 @@ export function ViewBoxAnnotatableComponent

() if (this.props.filterAddDocument?.(docs) === false || docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document) && Doc.LayoutField(doc) === Doc.LayoutField(this.props.Document))) { return false; } - const targetDataDoc = this.rootDoc[DocData]; + const targetDataDoc = this.dataDoc; const effectiveAcl = GetEffectiveAcl(targetDataDoc); if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) { diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index c1ec5b4a4..bd82f7782 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -574,12 +574,12 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV e.stopPropagation(); }; render() { - if (!this.view0) return null; - - const isText = this.view0.props.Document[this.view0.LayoutFieldKey] instanceof RichTextField; const doc = this.view0?.props.Document; - const considerPull = isText && this.considerGoogleDocsPull; - const considerPush = isText && this.considerGoogleDocsPush; + if (!doc || !this.view0) return null; + + const isText = () => doc[this.view0!.LayoutFieldKey] instanceof RichTextField; + const considerPull = () => isText() && this.considerGoogleDocsPull; + const considerPush = () => isText() && this.considerGoogleDocsPush; return (

@@ -608,11 +608,11 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
{this.recordButton}
{!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null :
{this.shareButton}
} {!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null : ( -
+
{this.considerGoogleDocsPush}
)} -
+
{this.considerGoogleDocsPull}
{this.menuButton}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d4b474de9..4ede2e2bb 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -6,7 +6,7 @@ import { observer } from 'mobx-react'; import { FaUndo } from 'react-icons/fa'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc'; -import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols'; +import { AclAdmin, AclAugment, AclEdit } from '../../fields/DocSymbols'; import { InkField } from '../../fields/InkField'; import { RichTextField } from '../../fields/RichTextField'; import { ScriptField } from '../../fields/ScriptField'; @@ -71,10 +71,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P e.clientY - center.y, NumCast(SelectionManager.Views().lastElement()?.screenToLocalTransform().Rotate)); (this._showNothing = !(this.Bounds.x !== Number.MAX_VALUE && // - (this.Bounds.x > center.x+x + this._resizeBorderWidth / 2 || - this.Bounds.r < center.x+x - this._resizeBorderWidth / 2 || - this.Bounds.y > center.y+y + this._resizeBorderWidth / 2 || - this.Bounds.b < center.y+y - this._resizeBorderWidth / 2))); + (this.Bounds.x > center.x+x || this.Bounds.r < center.x+x || + this.Bounds.y > center.y+y || this.Bounds.b < center.y+y ))); })); // prettier-ignore } @@ -551,8 +549,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (setData) Doc.SetNativeHeight(Doc.GetProto(doc), NumCast(doc._nativeHeight)); } - doc._width = NumCast(doc._width) * scale.x; - doc._height = NumCast(doc._height) * scale.y; + doc._width = Math.max(1, NumCast(doc._width) * scale.x); + doc._height = Math.max(1, NumCast(doc._height) * scale.y); const { deltaX, deltaY } = this.realignRefPt(doc, refCent, initWidth, initHeight); doc.x = NumCast(doc.x) + deltaX; doc.y = NumCast(doc.y) + deltaY; @@ -675,7 +673,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P seldocview.props.hideDeleteButton || seldocview.rootDoc.hideDeleteButton || SelectionManager.Views().some(docView => { - const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DocData]) : AclEdit; + const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().dataDoc) : AclEdit; return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin; }); const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => ( @@ -801,11 +799,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
- {seldocview.props.renderDepth <= 1 || !seldocview.props.docViewPath().lastElement() - ? null - : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectContainerDocClick, 'tap to select containing document')} )} + {seldocview.props.renderDepth <= 1 || !seldocview.props.docViewPath().lastElement() ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectContainerDocClick, 'tap to select containing document')} {useRounding && (
{SnappingManager.horizSnapLines().map((l, i) => ( - + ))} {SnappingManager.vertSnapLines().map((l, i) => ( - + ))}
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 20c7a08fa..8b8838464 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable, ObservableMap, runInAction, trace } from 'mobx'; +import { action, computed, observable, ObservableMap } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocData } from '../../fields/DocSymbols'; @@ -19,7 +19,7 @@ import React = require('react'); const _global = (window /* browser */ || global) /* node */ as any; export interface MarqueeAnnotatorProps { - rootDoc: Doc; + Document: Doc; down?: number[]; scrollTop: number; scaling?: () => number; @@ -69,8 +69,8 @@ export class MarqueeAnnotator extends React.Component { const marqueeAnno = Docs.Create.FreeformDocument([], { onClick: isLinkButton ? FollowLinkScript() : undefined, backgroundColor: color, - annotationOn: this.props.rootDoc, - title: 'Annotation on ' + this.props.rootDoc.title, + annotationOn: this.props.Document, + title: 'Annotation on ' + this.props.Document.title, }); marqueeAnno.x = NumCast(doc.freeform_panX_min) + (parseInt(anno.style.left || '0') - containerOffset[0]) / scale; marqueeAnno.y = NumCast(doc.freeform_panY_min) + (parseInt(anno.style.top || '0') - containerOffset[1]) / scale; @@ -82,13 +82,13 @@ export class MarqueeAnnotator extends React.Component { } const textRegionAnno = Docs.Create.HTMLMarkerDocument([], { - annotationOn: this.props.rootDoc, + annotationOn: this.props.Document, text: this.props.selectionText(), backgroundColor: 'transparent', presentation_duration: 2100, presentation_transition: 500, presentation_zoomText: true, - title: 'Selection on ' + this.props.rootDoc.title, + title: 'Selection on ' + this.props.Document.title, }); let minX = Number.MAX_VALUE; let maxX = -Number.MAX_VALUE; @@ -126,7 +126,7 @@ export class MarqueeAnnotator extends React.Component { @action highlight = (color: string, isLinkButton: boolean, savedAnnotations?: ObservableMap, addAsAnnotation?: boolean, summarize?: boolean) => { // creates annotation documents for current highlights - const effectiveAcl = GetEffectiveAcl(this.props.rootDoc[DocData]); + const effectiveAcl = GetEffectiveAcl(this.props.Document[DocData]); const annotationDoc = [AclAugment, AclSelfEdit, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color, isLinkButton, savedAnnotations); addAsAnnotation && annotationDoc && this.props.addDocument(annotationDoc); return annotationDoc as Doc; @@ -146,11 +146,11 @@ export class MarqueeAnnotator extends React.Component { const center = { x: boundingRect.x + boundingRect.width / 2, y: boundingRect.y + boundingRect.height / 2 }; const downPt = Utils.rotPt(down[0] - center.x, down[1] - center.y, NumCast(this.props.docView().screenToLocalTransform().Rotate)); const scale = this.props.docView().props.ScreenToLocalTransform().Scale; - const scalex = this.props.mainCont.offsetWidth / NumCast(this.props.rootDoc.width); - const scaley = this.props.mainCont.offsetHeight / NumCast(this.props.rootDoc.height); + const scalex = this.props.mainCont.offsetWidth / NumCast(this.props.Document.width); + const scaley = this.props.mainCont.offsetHeight / NumCast(this.props.Document.height); // set marquee x and y positions to the spatially transformed position - return { x: scalex * (downPt.x + NumCast(this.props.rootDoc.width) / scale / 2) * scale, - y: scaley * (downPt.y + NumCast(this.props.rootDoc.height) / scale / 2) * scale + this.props.annotationLayerScrollTop }; // prettier-ignore + return { x: scalex * (downPt.x + NumCast(this.props.Document.width) / scale / 2) * scale, + y: scaley * (downPt.y + NumCast(this.props.Document.height) / scale / 2) * scale + this.props.annotationLayerScrollTop }; // prettier-ignore }; @action @@ -184,14 +184,14 @@ export class MarqueeAnnotator extends React.Component { const sourceAnchorCreator = () => this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true, undefined, true); // hyperlink color const targetCreator = (annotationOn: Doc | undefined) => { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.props.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.props.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); FormattedTextBox.SelectOnLoad = target[Id]; return target; }; DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.docView(), sourceAnchorCreator, targetCreator), e.pageX, e.pageY, { dragComplete: e => { if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { - e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; + e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.Document; e.annoDragData.linkSourceDoc.followLinkZoom = false; } }, diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 18f53b8e7..84b1bf038 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -42,12 +42,15 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get selectedDoc() { return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.rootDoc; } + @computed get selectedLayoutDoc() { + return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.layoutDoc; + } @computed get selectedTabView() { return !SelectionManager.SelectedSchemaDoc() && SelectionManager.Views().lastElement()?.topMost; } propertyToggleBtn = (label: (on?: any) => string, property: string, tooltip: (on?: any) => string, icon: (on?: any) => any, onClick?: (dv: Opt, doc: Doc, property: string) => void, useUserDoc?: boolean) => { - const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedDoc; + const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedLayoutDoc; const onPropToggle = (dv: Opt, doc: Doc, prop: string) => ((dv?.layoutDoc || doc)[prop] = (dv?.layoutDoc || doc)[prop] ? false : true); return !targetDoc ? null : ( { } @computed get selectedDoc() { - return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.rootDoc || Doc.ActiveDashboard; + return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.Document || Doc.ActiveDashboard; + } + + @computed get selectedLayoutDoc() { + return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.layoutDoc || Doc.ActiveDashboard; } @computed get selectedDocumentView() { if (SelectionManager.Views().length) return SelectionManager.Views()[0]; @@ -126,13 +130,13 @@ export class PropertiesView extends React.Component { return [CollectionViewType.Stacking, CollectionViewType.NoteTaking].includes(this.selectedDoc?.type_collection as any); } - rtfWidth = () => (!this.selectedDoc ? 0 : Math.min(NumCast(this.selectedDoc?._width), this.props.width - 20)); - rtfHeight = () => (!this.selectedDoc ? 0 : this.rtfWidth() <= NumCast(this.selectedDoc?._width) ? Math.min(NumCast(this.selectedDoc?._height), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT); + rtfWidth = () => (!this.selectedLayoutDoc ? 0 : Math.min(NumCast(this.selectedLayoutDoc?._width), this.props.width - 20)); + rtfHeight = () => (!this.selectedLayoutDoc ? 0 : this.rtfWidth() <= NumCast(this.selectedLayoutDoc?._width) ? Math.min(NumCast(this.selectedLayoutDoc?._height), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT); @action docWidth = () => { - if (this.selectedDoc) { - const layoutDoc = this.selectedDoc; + const layoutDoc = this.selectedLayoutDoc; + if (layoutDoc) { const aspect = Doc.NativeAspect(layoutDoc, undefined, !layoutDoc._layout_fitWidth); if (aspect) return Math.min(NumCast(layoutDoc._width), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.width - 20)); return Doc.NativeWidth(layoutDoc) ? Math.min(NumCast(layoutDoc._width), this.props.width - 20) : this.props.width - 20; @@ -142,8 +146,8 @@ export class PropertiesView extends React.Component { @action docHeight = () => { - if (this.selectedDoc && this.dataDoc) { - const layoutDoc = this.selectedDoc; + const layoutDoc = this.selectedLayoutDoc; + if (layoutDoc && this.dataDoc) { return Math.max( 70, Math.min( @@ -288,7 +292,7 @@ export class PropertiesView extends React.Component { return (
{ */ @undoBatch changePermissions = (e: any, user: string) => { - const docs = (SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(dv => dv.props.Document)).filter(doc => doc).map(doc => (this.layoutDocAcls ? doc! : DocCast(doc)[DocData])); + const docs = SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(dv => (this.layoutDocAcls ? dv.layoutDoc : dv.dataDoc)); SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs, this.layoutDocAcls); }; @@ -453,7 +457,7 @@ export class PropertiesView extends React.Component { const individualTableEntries = []; const usersAdded: string[] = []; // all shared users being added - organized by denormalized email - const seldoc = this.layoutDocAcls || !this.selectedDoc ? this.selectedDoc : Doc.GetProto(this.selectedDoc); + const seldoc = this.layoutDocAcls ? this.selectedLayoutDoc : this.selectedDoc?.[DocData]; // adds each user to usersAdded SharingManager.Instance.users.forEach(eachUser => { var userOnDoc = true; @@ -630,10 +634,11 @@ export class PropertiesView extends React.Component { @action rotate = (angle: number) => { const _centerPoints: { X: number; Y: number }[] = []; - if (this.selectedDoc) { - const doc = this.selectedDoc; - if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) { - const ink = Cast(doc.data, InkField)?.inkData; + const doc = this.selectedDoc; + const layout = this.selectedLayoutDoc; + if (doc && layout) { + if (doc.type === DocumentType.INK && doc.x && doc.y && layout._width && layout._height && doc.data) { + const ink = Cast(doc.stroke, InkField)?.inkData; if (ink) { const xs = ink.map(p => p.X); const ys = ink.map(p => p.Y); @@ -646,9 +651,9 @@ export class PropertiesView extends React.Component { } var index = 0; - if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) { - doc.rotation = NumCast(doc.rotation) + angle; - const inks = Cast(doc.data, InkField)?.inkData; + if (doc.type === DocumentType.INK && doc.x && doc.y && layout._width && layout._height && doc.data) { + layout.rotation = NumCast(layout.rotation) + angle; + const inks = Cast(doc.stroke, InkField)?.inkData; if (inks) { const newPoints: { X: number; Y: number }[] = []; inks.forEach(ink => { @@ -656,7 +661,7 @@ export class PropertiesView extends React.Component { const newY = Math.sin(angle) * (ink.X - _centerPoints[index].X) + Math.cos(angle) * (ink.Y - _centerPoints[index].Y) + _centerPoints[index].Y; newPoints.push({ X: newX, Y: newY }); }); - doc.data = new InkField(newPoints); + doc.stroke = new InkField(newPoints); const xs = newPoints.map(p => p.X); const ys = newPoints.map(p => p.Y); const left = Math.min(...xs); @@ -664,8 +669,8 @@ export class PropertiesView extends React.Component { const right = Math.max(...xs); const bottom = Math.max(...ys); - doc._height = bottom - top; - doc._width = right - left; + layout._height = bottom - top; + layout._width = right - left; } index++; } @@ -1178,7 +1183,7 @@ export class PropertiesView extends React.Component { return ( <> (this.openAppearance = bool)} onDoubleClick={() => this.CloseAll()}> - {this.selectedDoc?.layout_isSvg ? this.appearanceEditor : null} + {this.selectedLayoutDoc?.layout_isSvg ? this.appearanceEditor : null} (this.openTransform = bool)} onDoubleClick={() => this.CloseAll()}> {this.transformEditor} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 2162d8878..5399d38b4 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -122,7 +122,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt, props: Opt, props: Opt(docs); } else { - Doc.SetInPlace(this.rootDoc, 'dockingConfig', json, true); - Doc.SetInPlace(this.rootDoc, 'data', new List(docs), true); + Doc.SetInPlace(this.Document, 'dockingConfig', json, true); + Doc.SetInPlace(this.Document, 'data', new List(docs), true); } } this._flush?.end(); @@ -479,9 +479,9 @@ export class CollectionDockingView extends CollectionSubView() { tabDestroyed = (tab: any) => { this._flush = this._flush ?? UndoManager.StartBatch('tab movement'); if (tab.DashDoc && ![DocumentType.PRES].includes(tab.DashDoc?.type) && !tab.contentItem.config.props.keyValue) { - Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc); + Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc, undefined, undefined, true); // if you close a tab that is not embedded somewhere else (an embedded Doc can be opened simultaneously in a tab), then add the tab to recently closed - if (tab.DashDoc.embedContainer === this.rootDoc) tab.DashDoc.embedContainer = undefined; + if (tab.DashDoc.embedContainer === this.Document) tab.DashDoc.embedContainer = undefined; if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true); Doc.RemoveDocFromList(Doc.GetProto(tab.DashDoc), 'proto_embeddings', tab.DashDoc); } @@ -512,28 +512,31 @@ export class CollectionDockingView extends CollectionSubView() { _layout_fitWidth: true, title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`, }); - Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd); - inheritParentAcls(this.rootDoc, docToAdd, false); + Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd, undefined, undefined, true); + inheritParentAcls(this.Document, docToAdd, false); CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack); } }); - let addNewDoc = action(() => { - const dashboard = Doc.ActiveDashboard; - if (dashboard) { - dashboard['pane-count'] = NumCast(dashboard['pane-count']) + 1; - const docToAdd = Docs.Create.FreeformDocument([], { - _width: this.props.PanelWidth(), - _height: this.props.PanelHeight(), - _layout_fitWidth: true, - _freeform_backgroundGrid: true, - title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`, - }); - Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd); - inheritParentAcls(this.dataDoc, docToAdd, false); - CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack); - } - }); + let addNewDoc = undoable( + action(() => { + const dashboard = Doc.ActiveDashboard; + if (dashboard) { + dashboard['pane-count'] = NumCast(dashboard['pane-count']) + 1; + const docToAdd = Docs.Create.FreeformDocument([], { + _width: this.props.PanelWidth(), + _height: this.props.PanelHeight(), + _layout_fitWidth: true, + _freeform_backgroundGrid: true, + title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`, + }); + Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd, undefined, undefined, true); + inheritParentAcls(this.dataDoc, docToAdd, false); + CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack); + } + }), + 'add new tab' + ); stack.header?.controlsContainer .find('.lm_close') //get the close icon @@ -569,7 +572,7 @@ export class CollectionDockingView extends CollectionSubView() { }; render() { - const href = ImageCast(this.rootDoc.thumb)?.url?.href; + const href = ImageCast(this.Document.thumb)?.url?.href; return this.props.renderDepth > -1 ? (
{href ? ( diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index b190eb23d..3c555e731 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -1,43 +1,26 @@ import React = require('react'); -import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { FontAwesomeIcon, FontAwesomeIconProps } from '@fortawesome/react-fontawesome'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { Toggle, ToggleType, Type } from 'browndash-components'; import { action, computed, Lambda, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { ColorState } from 'react-color'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; -import { Document } from '../../../fields/documentSchemas'; -import { Id } from '../../../fields/FieldSymbols'; -import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { RichTextField } from '../../../fields/RichTextField'; -import { listSpec } from '../../../fields/Schema'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types'; -import { GestureUtils } from '../../../pen-gestures/GestureUtils'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../Utils'; -import { Docs } from '../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; -import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; import { AntimodeMenu } from '../AntimodeMenu'; import { EditableView } from '../EditableView'; -import { GestureOverlay } from '../GestureOverlay'; -import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from '../InkingStroke'; -import { LightboxView } from '../LightboxView'; import { MainView } from '../MainView'; -import { media_state } from '../nodes/AudioBox'; -import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; -import { DocumentView, DocumentViewInternal, OpenWhereMod } from '../nodes/DocumentView'; -import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; +import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; -import { CollectionDockingView } from './CollectionDockingView'; -import { CollectionFreeFormView } from './collectionFreeForm'; import { CollectionLinearView } from './collectionLinear'; import './CollectionMenu.scss'; @@ -66,7 +49,7 @@ export class CollectionMenu extends AntimodeMenu { componentDidMount() { reaction( - () => SelectionManager.Views().length && SelectionManager.Views()[0], + () => SelectionManager.Views().lastElement(), view => view && this.SetSelection(view) ); } @@ -174,7 +157,6 @@ export class CollectionMenu extends AntimodeMenu {
); - // NEW BUTTONS //dash col linear view buttons const contMenuButtons = (
{ ); return contMenuButtons; - - // const button = Pin Menu
} key="pin menu" placement="bottom"> - // - // ; - - // //OLD BUTTONS - // return this.getElement(!this.SelectedCollection ? [/*button*/] : - // [, - // prop, - // /*button*/]); } } @@ -228,7 +195,7 @@ export class CollectionViewBaseChrome extends React.Component { let formatStr = source.length && Cast(source[0].text, RichTextField, null)?.Text; try { @@ -250,24 +217,24 @@ export class CollectionViewBaseChrome extends React.Component source.length && (this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]))), initialize: emptyFunction, }; _contentCommand = { params: ['target', 'source'], title: 'set content', - script: 'getProto(self.target).data = copyField(self.source);', + script: 'getProto(this.target).data = copyField(this.source);', immediate: undoBatch((source: Doc[]) => (Doc.GetProto(this.target).data = new List(source))), initialize: emptyFunction, }; _onClickCommand = { params: ['target', 'proxy'], title: 'copy onClick', - script: `{ if (self.proxy?.[0]) { - getProto(self.proxy[0]).onClick = copyField(self.target.onClick); - getProto(self.proxy[0]).target = self.target.target; - getProto(self.proxy[0]).source = copyField(self.target.source); + script: `{ if (this.proxy?.[0]) { + getProto(this.proxy[0]).onClick = copyField(this.target.onClick); + getProto(this.proxy[0]).target = this.target.target; + getProto(this.proxy[0]).source = copyField(this.target.source); }}`, immediate: undoBatch((source: Doc[]) => {}), initialize: emptyFunction, @@ -275,7 +242,7 @@ export class CollectionViewBaseChrome extends React.Component { this.target._freeform_panX = 0; this.target._freeform_panY = 0; @@ -292,22 +259,22 @@ export class CollectionViewBaseChrome extends React.Component (this.target._freeform_fitContentsToBox = !this.target._freeform_fitContentsToBox)), initialize: emptyFunction, }; _fitContentCommand = { params: ['target'], title: 'toggle clusters', - script: 'self.target._freeform_useClusters = !self.target._freeform_useClusters;', + script: 'this.target._freeform_useClusters = !this.target._freeform_useClusters;', immediate: undoBatch((source: Doc[]) => (this.target._freeform_useClusters = !this.target._freeform_useClusters)), initialize: emptyFunction, }; _saveFilterCommand = { params: ['target'], title: 'save filter', - script: `self.target._childFilters = compareLists(self['target-childFilters'],self.target._childFilters) ? undefined : copyField(self['target-childFilters']); - self.target._searchFilterDocs = compareLists(self['target-searchFilterDocs'],self.target._searchFilterDocs) ? undefined: copyField(self['target-searchFilterDocs']);`, + script: `this.target._childFilters = compareLists(this['target-childFilters'],this.target._childFilters) ? undefined : copyField(this['target-childFilters']); + this.target._searchFilterDocs = compareLists(this['target-searchFilterDocs'],this.target._searchFilterDocs) ? undefined: copyField(this['target-searchFilterDocs']);`, immediate: undoBatch((source: Doc[]) => { this.target._childFilters = undefined; this.target._searchFilterDocs = undefined; @@ -390,57 +357,6 @@ export class CollectionViewBaseChrome extends React.Component; - case CollectionViewType.Stacking: - return ; - case CollectionViewType.NoteTaking: - return ; - case CollectionViewType.Schema: - return ; - case CollectionViewType.Tree: - return ; - case CollectionViewType.Masonry: - return ; - case CollectionViewType.Carousel: - case CollectionViewType.Carousel3D: - return ; - case CollectionViewType.Grid: - return ; - case CollectionViewType.Docking: - return ; - } - } - - @computed get otherSubChrome() { - const docType = this.props.docView.Document.type; - switch (docType) { - default: - return null; - case DocumentType.IMG: - return ; - case DocumentType.PDF: - return ; - case DocumentType.INK: - return ; - case DocumentType.WEB: - return ; - case DocumentType.VID: - return ; - case DocumentType.RTF: - return ; - case DocumentType.MAP: - return ; - } - } - private dropDisposer?: DragManager.DragDropDisposer; protected createDropTarget = (ele: HTMLDivElement) => { this.dropDisposer?.(); @@ -517,593 +433,11 @@ export class CollectionViewBaseChrome extends React.Component ); } - - @computed get viewModes() { - const excludedViewTypes = [CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.StackedTimeline, CollectionViewType.Linear]; - const isPres: boolean = this.document && this.document.type === DocumentType.PRES; - return isPres ? null : ( -
- drop document to apply or drag to create button
} placement="bottom"> -
- - -
- -
- ); - } - - @computed get selectedDocumentView() { - return SelectionManager.Views().lastElement(); - } - @computed get selectedDoc() { - return SelectionManager.Docs().lastElement(); - } - @computed get notACollection() { - if (this.selectedDoc) { - const layoutField = Doc.LayoutField(this.selectedDoc); - return this.props.type === CollectionViewType.Docking || (typeof layoutField === 'string' && !layoutField?.includes('CollectionView')); - } else return false; - } - - @undoBatch - @action - startRecording = () => { - const doc = Docs.Create.ScreenshotDocument({ title: 'screen recording', _layout_fitWidth: true, _width: 400, _height: 200, mediaState: media_state.PendingRecording }); - CollectionDockingView.AddSplit(doc, OpenWhereMod.right); - }; - - @computed - get recordButton() { - const targetDoc = this.selectedDoc; - return ( - {'Capture screen'}
} placement="top"> - - - ); - } - - @undoBatch - onEmbed = () => { - if (this.selectedDoc && this.selectedDocumentView) { - // const copy = Doc.MakeCopy(this.selectedDocumentView.props.Document, true); - // copy.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width); - // copy.y = NumCast(this.selectedDoc.y) + 30; - // this.selectedDocumentView.props.addDocument?.(copy); - const embedding = Doc.MakeEmbedding(this.selectedDoc); - embedding.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width); - embedding.y = NumCast(this.selectedDoc.y) + 30; - this.selectedDocumentView.props.addDocument?.(embedding); - } - }; - onEmbedButtonDown = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, this.onEmbedButtonMoved, emptyFunction, emptyFunction); - }; - - @undoBatch - onEmbedButtonMoved = (e: PointerEvent) => { - const contentDiv = this.selectedDocumentView?.ContentDiv; - if (contentDiv && this.selectedDoc) { - const dragData = new DragManager.DocumentDragData([this.selectedDoc]); - const offset = [e.clientX - contentDiv.getBoundingClientRect().x, e.clientY - contentDiv.getBoundingClientRect().y]; - dragData.defaultDropAction = 'embed'; - dragData.canEmbed = true; - DragManager.StartDocumentDrag([contentDiv], dragData, e.clientX, e.clientY, { - offsetX: offset[0], - offsetY: offset[1], - hideSource: false, - }); - return true; - } - return false; - }; - - @computed - get embedButton() { - const targetDoc = this.selectedDoc; - return !targetDoc || targetDoc.type === DocumentType.PRES ? null : ( - {'Tap or Drag to create an embedding'}
} placement="top"> - - - ); - } - - @computed get lightboxButton() { - const targetDoc = this.selectedDoc; - return !targetDoc ? null : ( - {'View in Lightbox'}
} placement="top"> - - - ); - } - - @computed get toggleOverlayButton() { - return ( - <> - Toggle Overlay Layer
} placement="bottom"> - - - - ); - } - render() { return (
-
- {this.notACollection || this.props.type === CollectionViewType.Invalid ? null : this.viewModes} -
- {this.embedButton} - {/* {this.pinButton} */} - {this.toggleOverlayButton} -
- {this.subChrome} -
- {this.lightboxButton} - {this.recordButton} - {!this._buttonizableCommands ? null : this.templateChrome} -
-
-
- ); - } -} - -@observer -export class CollectionDockingChrome extends React.Component { - render() { - return null; - } -} - -@observer -export class CollectionFreeFormViewChrome extends React.Component { - public static Instance: CollectionFreeFormViewChrome; - constructor(props: any) { - super(props); - CollectionFreeFormViewChrome.Instance = this; - } - get document() { - return this.props.docView.props.Document; - } - @computed get dataField() { - return this.document[this.props.docView.LayoutFieldKey + (this.props.isOverlay ? '_annotations' : '')]; - } - @computed get childDocs() { - return DocListCast(this.dataField); - } - @computed get selectedDocumentView() { - return SelectionManager.Views().lastElement(); - } - @computed get selectedDoc() { - return SelectionManager.Docs().lastElement(); - } - @computed get isText() { - return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false; - } - - public static gotoKeyFrame(doc: Doc, newFrame: number) { - if (doc) { - const childDocs = DocListCast(doc[Doc.LayoutFieldKey(doc)]); - const currentFrame = Cast(doc._currentFrame, 'number', null); - if (currentFrame === undefined) { - doc._currentFrame = 0; - CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0); - } - CollectionFreeFormView.updateKeyframe(undefined, [...childDocs, doc], currentFrame || 0); - doc._currentFrame = newFrame === undefined ? 0 : Math.max(0, newFrame); - } - } - - _keyTimer: NodeJS.Timeout | undefined; - @undoBatch - @action - nextKeyframe = (): void => { - const currentFrame = Cast(this.document._currentFrame, 'number', null); - if (currentFrame === undefined) { - this.document._currentFrame = 0; - CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); - } - this._keyTimer = CollectionFreeFormView.updateKeyframe(this._keyTimer, [...this.childDocs, this.document], currentFrame || 0); - this.document._currentFrame = Math.max(0, (currentFrame || 0) + 1); - this.document.lastFrame = Math.max(NumCast(this.document._currentFrame), NumCast(this.document.lastFrame)); - }; - @undoBatch - @action - prevKeyframe = (): void => { - const currentFrame = Cast(this.document._currentFrame, 'number', null); - if (currentFrame === undefined) { - this.document._currentFrame = 0; - CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); - } - this._keyTimer = CollectionFreeFormView.gotoKeyframe(this._keyTimer, [...this.childDocs, this.document], 1000); - this.document._currentFrame = Math.max(0, (currentFrame || 0) - 1); - }; - - private _palette = ['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '']; - private _width = ['1', '5', '10', '100']; - private _dotsize = [10, 20, 30, 40]; - private _draw = ['∿', '=', '⎯', '→', '↔︎', 'ロ', 'O']; - private _head = ['', '', '', '', 'arrow', '', '']; - private _end = ['', '', '', 'arrow', 'arrow', '', '']; - private _shapePrims = ['', '', 'line', 'line', 'line', 'rectangle', 'circle'] as GestureUtils.Gestures[]; - private _title = ['pen', 'highlighter', 'line', 'line with arrow', 'line with double arrows', 'square', 'circle']; - private _faName = ['pen-fancy', 'highlighter', 'minus', 'long-arrow-alt-right', 'arrows-alt-h', 'square', 'circle']; - @observable _selectedPrimitive = this._shapePrims.length; - @observable _keepPrimitiveMode = false; // for whether primitive selection enters a one-shot or persistent mode - @observable _colorBtn = false; - @observable _widthBtn = false; - @observable _fillBtn = false; - - @action clearKeepPrimitiveMode() { - this._selectedPrimitive = this._shapePrims.length; - } - @action primCreated() { - if (!this._keepPrimitiveMode) { - //get out of ink mode after each stroke= - if (Doc.ActiveTool === InkTool.Highlighter && GestureOverlay.Instance.SavedColor) SetActiveInkColor(GestureOverlay.Instance.SavedColor); - Doc.ActiveTool = InkTool.None; - this._selectedPrimitive = this._shapePrims.length; - SetActiveArrowStart('none'); - SetActiveArrowEnd('none'); - } - } - - @action - changeColor = (color: string, type: string) => { - const col: ColorState = { - hex: color, - hsl: { a: 0, h: 0, s: 0, l: 0, source: '' }, - hsv: { a: 0, h: 0, s: 0, v: 0, source: '' }, - rgb: { a: 0, r: 0, b: 0, g: 0, source: '' }, - oldHue: 0, - source: '', - }; - if (type === 'color') { - SetActiveInkColor(Utils.colorString(col)); - } else if (type === 'fill') { - SetActiveFillColor(Utils.colorString(col)); - } - }; - - @action - editProperties = (value: any, field: string) => { - SelectionManager.Views().forEach( - action((element: DocumentView) => { - const doc = Document(element.rootDoc); - if (doc.type === DocumentType.INK) { - switch (field) { - case 'width': - doc.stroke_width = Number(value); - break; - case 'color': - doc.color = String(value); - break; - case 'fill': - doc.fillColor = String(value); - break; - case 'dash': - doc.stroke_dash = value; - } - } - }) - ); - }; - - @computed get drawButtons() { - const func = action((e: React.MouseEvent | React.PointerEvent, i: number, keep: boolean) => { - this._keepPrimitiveMode = keep; - // these are for shapes - if (this._selectedPrimitive !== i) { - this._selectedPrimitive = i; - if (this._title[i] === 'highlighter') { - Doc.ActiveTool = InkTool.Highlighter; - GestureOverlay.Instance.SavedColor = ActiveInkColor(); - SetActiveInkColor('rgba(245, 230, 95, 0.75)'); - } else { - Doc.ActiveTool = InkTool.Pen; - } - SetActiveArrowStart(this._head[i]); - SetActiveArrowEnd(this._end[i]); - SetActiveBezierApprox('300'); - - if (GestureOverlay.Instance) GestureOverlay.Instance.InkShape = this._shapePrims[i]; - } else { - this._selectedPrimitive = this._shapePrims.length; - Doc.ActiveTool = InkTool.None; - SetActiveArrowStart(''); - SetActiveArrowEnd(''); - if (GestureOverlay.Instance) GestureOverlay.Instance.InkShape = undefined; - SetActiveBezierApprox('0'); - } - e.stopPropagation(); - }); - return ( -
- {this._draw.map((icon, i) => ( - {this._title[i]}
} placement="bottom"> - - - ))} -
- ); - } - - toggleButton = (key: string, value: boolean, setter: () => {}, icon: FontAwesomeIconProps['icon'], ele: JSX.Element | null) => { - return ( - {key}
} placement="bottom"> - - - ); - }; - - @computed get widthPicker() { - const widthPicker = this.toggleButton('stroke width', this._widthBtn, () => (this._widthBtn = !this._widthBtn), 'bars', null); - return !this._widthBtn ? ( - widthPicker - ) : ( -
- {widthPicker} - {this._width.map((wid, i) => ( - change width
} placement="bottom"> - - - ))} -
- ); - } - - @computed get colorPicker() { - const colorPicker = this.toggleButton('stroke color', this._colorBtn, () => (this._colorBtn = !this._colorBtn), 'pen-nib',
); - return !this._colorBtn ? ( - colorPicker - ) : ( -
- {colorPicker} - {this._palette.map(color => ( - - ))} -
- ); - } - @computed get fillPicker() { - const fillPicker = this.toggleButton('shape fill color', this._fillBtn, () => (this._fillBtn = !this._fillBtn), 'fill-drip',
); - return !this._fillBtn ? ( - fillPicker - ) : ( -
- {fillPicker} - {this._palette.map(color => ( - - ))} -
- ); - } - - render() { - return !this.props.docView.layoutDoc ? null : ( -
- - {!this.isText ? ( - <> - {this.drawButtons} - {this.widthPicker} - {this.colorPicker} - {this.fillPicker} - {Doc.noviceMode || this.props.isDoc ? null : ( - <> - Back Frame
} placement="bottom"> -
- -
- - Frame number
} placement="bottom"> -
this.props.docView.ComponentView?.setKeyFrameEditing?.(!this.props.docView.ComponentView?.getKeyFrameEditing?.()))}> - {NumCast(this.document._currentFrame)} -
- - Forward Frame
} placement="bottom"> -
- -
- - - )} - - ) : null} - {!this.selectedDocumentView?.ComponentView?.menuControls ? null : this.selectedDocumentView?.ComponentView?.menuControls?.()} - - ); - } -} -@observer -export class CollectionStackingViewChrome extends React.Component { - @observable private _currentKey: string = ''; - @observable private suggestions: string[] = []; - - get document() { - return this.props.docView.props.Document; - } - - @computed private get descending() { - return StrCast(this.document._columnsSort) === 'descending'; - } - @computed get pivotField() { - return StrCast(this.document._pivotField); - } - - getKeySuggestions = async (value: string): Promise => { - const val = value.toLowerCase(); - const docs = DocListCast(this.document[this.props.fieldKey]); - - if (Doc.noviceMode) { - if (docs instanceof Doc) { - const keys = Object.keys(docs).filter(key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('author_date') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0].toUpperCase() === key[0] && key[0] !== '_')); - return keys.filter(key => key.toLowerCase().indexOf(val) > -1); - } - const keys = new Set(); - docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); - const noviceKeys = Array.from(keys).filter(key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('author_date') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0]?.toUpperCase() === key[0] && key[0] !== '_')); - return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1); - } - - if (docs instanceof Doc) { - return Object.keys(docs).filter(key => key.toLowerCase().indexOf(val) > -1); - } else { - const keys = new Set(); - docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); - return Array.from(keys).filter(key => key.toLowerCase().indexOf(val) > -1); - } - }; - - @action - onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => { - this._currentKey = newValue; - }; - - getSuggestionValue = (suggestion: string) => suggestion; - - renderSuggestion = (suggestion: string) => { - return

{suggestion}

; - }; - - onSuggestionFetch = async ({ value }: { value: string }) => { - const sugg = await this.getKeySuggestions(value); - runInAction(() => { - this.suggestions = sugg; - }); - }; - - @action - onSuggestionClear = () => { - this.suggestions = []; - }; - - @action - setValue = (value: string) => { - this.document._pivotField = value; - return true; - }; - - @action toggleSort = () => { - this.document._columnsSort = this.document._columnsSort === 'descending' ? 'ascending' : this.document._columnsSort === 'ascending' ? undefined : 'descending'; - }; - @action resetValue = () => { - this._currentKey = this.pivotField; - }; - - render() { - const doctype = this.props.docView.Document.type; - const isPres: boolean = doctype === DocumentType.PRES; - return isPres ? null : ( -
-
-
GROUP BY:
-
- -
-
- this.pivotField} - autosuggestProps={{ - resetValue: this.resetValue, - value: this._currentKey, - onChange: this.onKeyChange, - autosuggestProps: { - inputProps: { - value: this._currentKey, - onChange: this.onKeyChange, - }, - getSuggestionValue: this.getSuggestionValue, - suggestions: this.suggestions, - alwaysRenderSuggestions: true, - renderSuggestion: this.renderSuggestion, - onSuggestionsFetchRequested: this.onSuggestionFetch, - onSuggestionsClearRequested: this.onSuggestionClear, - }, - }} - oneLine - SetValue={this.setValue} - contents={this.pivotField ? this.pivotField : 'N/A'} - /> -
+
{!this._buttonizableCommands ? null : this.templateChrome}
); @@ -1230,123 +564,6 @@ export class CollectionNoteTakingViewChrome extends React.Component { - // private _textwrapAllRows: boolean = Cast(this.document.textwrappedSchemaRows, listSpec("string"), []).length > 0; - get document() { - return this.props.docView.props.Document; - } - - @undoBatch - togglePreview = () => { - const dividerWidth = 4; - const borderWidth = 0; - const panelWidth = this.props.docView.props.PanelWidth(); - const previewWidth = NumCast(this.document.schema_previewWidth); - const tableWidth = panelWidth - 2 * borderWidth - dividerWidth - previewWidth; - this.document.schema_previewWidth = previewWidth === 0 ? Math.min(tableWidth / 3, 200) : 0; - }; - - @undoBatch - @action - toggleTextwrap = async () => { - const textwrappedRows = Cast(this.document.textwrappedSchemaRows, listSpec('string'), []); - if (textwrappedRows.length) { - this.document.textwrappedSchemaRows = new List([]); - } else { - const docs = DocListCast(this.document[this.props.fieldKey]); - const allRows = docs instanceof Doc ? [docs[Id]] : docs.map(doc => doc[Id]); - this.document.textwrappedSchemaRows = new List(allRows); - } - }; - - render() { - const previewWidth = NumCast(this.document.schema_previewWidth); - const textWrapped = Cast(this.document.textwrappedSchemaRows, listSpec('string'), []).length > 0; - - return ( -
-
-
Show Preview:
-
-
{previewWidth !== 0 ? 'on' : 'off'}
-
-
-
- ); - } -} - -@observer -export class CollectionTreeViewChrome extends React.Component { - get document() { - return this.props.docView.props.Document; - } - get sortAscending() { - return this.document[this.props.fieldKey + '-sortAscending']; - } - set sortAscending(value) { - this.document[this.props.fieldKey + '-sortAscending'] = value; - } - @computed private get ascending() { - return Cast(this.sortAscending, 'boolean', null); - } - - @action toggleSort = () => { - if (this.sortAscending) this.sortAscending = undefined; - else if (this.sortAscending === undefined) this.sortAscending = false; - else this.sortAscending = true; - }; - - render() { - return ( -
- -
- ); - } -} - -// Enter scroll speed for 3D Carousel -@observer -export class Collection3DCarouselViewChrome extends React.Component { - get document() { - return this.props.docView.props.Document; - } - @computed get scrollSpeed() { - return this.document._autoScrollSpeed; - } - - @action - setValue = (value: string) => { - const numValue = Number(StrCast(value)); - if (numValue > 0) { - this.document._autoScrollSpeed = numValue; - return true; - } - return false; - }; - - render() { - return ( -
-
- {/* {FormattedTextBox.Focused ? : null} */} -
AUTOSCROLL SPEED:
-
- StrCast(this.scrollSpeed)} oneLine SetValue={this.setValue} contents={this.scrollSpeed ? this.scrollSpeed : 1000} /> -
-
-
- ); - } -} - /** * Chrome for grid view. */ @@ -1492,12 +709,6 @@ export class CollectionGridViewChrome extends React.Component - {/* - - - - ) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} /> - */} @@ -1526,6 +737,3 @@ export class CollectionGridViewChrome extends React.Component (dref = r || undefined)} Document={doc} - pointerEvents={this.blockPointerEventsWhenDragging} DataDoc={dataDoc ?? (!Doc.AreProtosEqual(doc[DocData], doc) ? doc[DocData] : undefined)} + pointerEvents={this.blockPointerEventsWhenDragging} renderDepth={this.props.renderDepth + 1} PanelWidth={width} PanelHeight={height} @@ -635,7 +635,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { key="notes" style={{ overflowY: this.props.isContentActive() ? 'auto' : 'hidden', - background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor), + background: this.props.styleProvider?.(this.Document, this.props, StyleProp.BackgroundColor), pointerEvents: this.backgroundEvents, }} onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))} diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index abb12a8ab..ad8144466 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -43,7 +43,7 @@ export class CollectionPileView extends CollectionSubView() { removePileDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => { (doc instanceof Doc ? [doc] : doc).forEach(d => Doc.deiconifyView(d)); const ret = this.props.moveDocument?.(doc, targetCollection, addDoc) || false; - if (ret && !DocListCast(this.rootDoc[this.fieldKey ?? 'data']).length) this.props.DocumentView?.().props.removeDocument?.(this.rootDoc); + if (ret && !DocListCast(this.dataDoc[this.fieldKey ?? 'data']).length) this.props.DocumentView?.().props.removeDocument?.(this.Document); return ret; }; @@ -78,12 +78,12 @@ export class CollectionPileView extends CollectionSubView() { toggleStarburst = action(() => { this.layoutDoc._freeform_scale = undefined; if (this.layoutEngine() === computeStarburstLayout.name) { - if (NumCast(this.rootDoc._width) !== NumCast(this.rootDoc._starburstDiameter, 500)) { - this.rootDoc._starburstDiameter = NumCast(this.rootDoc._width); + if (NumCast(this.layoutDoc._width) !== NumCast(this.Document._starburstDiameter, 500)) { + this.Document._starburstDiameter = NumCast(this.layoutDoc._width); } const defaultSize = 110; - this.rootDoc.x = NumCast(this.rootDoc.x) + NumCast(this.layoutDoc._width) / 2 - NumCast(this.layoutDoc._freeform_pileWidth, defaultSize) / 2; - this.rootDoc.y = NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) / 2 - NumCast(this.layoutDoc._freeform_pileHeight, defaultSize) / 2; + this.Document.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width) / 2 - NumCast(this.layoutDoc._freeform_pileWidth, defaultSize) / 2; + this.Document.y = NumCast(this.Document.y) + NumCast(this.layoutDoc._height) / 2 - NumCast(this.layoutDoc._freeform_pileHeight, defaultSize) / 2; this.layoutDoc._width = NumCast(this.layoutDoc._freeform_pileWidth, defaultSize); this.layoutDoc._height = NumCast(this.layoutDoc._freeform_pileHeight, defaultSize); DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false); @@ -91,9 +91,9 @@ export class CollectionPileView extends CollectionSubView() { this.layoutDoc._freeform_panY = -10; this.props.Document._freeform_pileEngine = computePassLayout.name; } else { - const defaultSize = NumCast(this.rootDoc._starburstDiameter, 400); - this.rootDoc.x = NumCast(this.rootDoc.x) + NumCast(this.layoutDoc._width) / 2 - defaultSize / 2; - this.rootDoc.y = NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) / 2 - defaultSize / 2; + const defaultSize = NumCast(this.Document._starburstDiameter, 400); + this.Document.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width) / 2 - defaultSize / 2; + this.Document.y = NumCast(this.Document.y) + NumCast(this.layoutDoc._height) / 2 - defaultSize / 2; this.layoutDoc._freeform_pileWidth = NumCast(this.layoutDoc._width); this.layoutDoc._freeform_pileHeight = NumCast(this.layoutDoc._height); this.layoutDoc._freeform_panX = this.layoutDoc._freeform_panY = 0; diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 3351ca48e..7bde2cb5f 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -192,7 +192,7 @@ export class CollectionStackedTimeline extends CollectionSubView 15 && !this.IsTrimming) { - const anchor = CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this._markerStart, this._markerEnd, undefined, true); + const anchor = CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.props.fieldKey, this._markerStart, this._markerEnd, undefined, true); setTimeout(() => DocumentManager.Instance.getDocumentView(anchor)?.select(false)); } (!isClick || !wasSelecting) && (this._markerEnd = undefined); @@ -274,7 +274,7 @@ export class CollectionStackedTimeline extends CollectionSubView { if (shiftKey) { - CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.currentTime, undefined, undefined, true); + CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.props.fieldKey, this.currentTime, undefined, undefined, true); } else { !wasPlaying && this.props.setTime(this.toTimeline(clientX - rect.x, rect.width)); } @@ -388,8 +388,8 @@ export class CollectionStackedTimeline extends CollectionSubView, anchorEndTime: Opt, docAnchor: Opt, addAsAnnotation: boolean) { - if (anchorStartTime === undefined) return rootDoc; + static createAnchor(doc: Doc, dataDoc: Doc, fieldKey: string, anchorStartTime: Opt, anchorEndTime: Opt, docAnchor: Opt, addAsAnnotation: boolean) { + if (anchorStartTime === undefined) return doc; const startTag = '_timecodeToShow'; const endTag = '_timecodeToHide'; const anchor = @@ -402,7 +402,7 @@ export class CollectionStackedTimeline extends CollectionSubView e.stopPropagation()} + onWheel={e => this.isContentActive() && e.stopPropagation()} onScroll={this.setScroll} onMouseMove={e => this.isContentActive() && this.onHover(e)} ref={wrapper => (this._timelineWrapper = wrapper)}> @@ -775,7 +775,7 @@ class StackedTimelineAnchor extends React.Component // context menu contextMenuItems = () => { const resetTitle = { - script: ScriptField.MakeFunction(`self.title = self["${this.props.endTag}"] ? "#" + formatToTime(self["${this.props.startTag}"]) + "-" + formatToTime(self["${this.props.endTag}"]) : "#" + formatToTime(self["${this.props.startTag}"])`)!, + script: ScriptField.MakeFunction(`this.title = this["${this.props.endTag}"] ? "#" + formatToTime(this["${this.props.startTag}"]) + "-" + formatToTime(this["${this.props.endTag}"]) : "#" + formatToTime(this["${this.props.startTag}"])`)!, icon: 'folder-plus', label: 'Reset Title', }; diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index dddb3ec71..165ccbdb1 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -142,7 +142,7 @@ transform-origin: top left; grid-column-end: span 1; height: 100%; - margin: auto; + //margin: auto; display: inline-grid; } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index da00093dd..5b86aaf86 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -9,7 +9,7 @@ import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; -import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; import { emptyFunction, returnEmptyDoclist, returnFalse, returnNone, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; @@ -309,12 +309,14 @@ export class CollectionStackingView extends CollectionSubView (this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined); @observable docRefs = new ObservableMap(); + childFitWidth = (doc: Doc) => Cast(this.Document.childLayoutFitWidth, 'boolean', this.props.childLayoutFitWidth?.(doc) ?? Cast(doc.layout_fitWidth, 'boolean', null)); // this is what renders the document that you see on the screen // called in Children: this actually adds a document to our children list getDisplayDoc(doc: Doc, width: () => number, count: number) { const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField ? undefined : this.props.DataDoc; const height = () => this.getDocHeight(doc); - + const panelHeight = () => (this.isStackingView ? height() : Math.min(height(), this.props.PanelHeight())); + const panelWidth = () => (this.isStackingView ? width() : this.columnWidth); const stackedDocTransform = () => this.getDocTransform(doc); this._docXfs.push({ stackedDocTransform, width, height }); return count > this._renderCount ? null : ( @@ -323,21 +325,21 @@ export class CollectionStackingView extends CollectionSubView (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1)); - const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? NumCast(d._width) : 0); - const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? NumCast(d._height) : 0); + const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!this.childFitWidth(childLayoutDoc) ? NumCast(d._width) : 0); + const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!this.childFitWidth(childLayoutDoc) ? NumCast(d._height) : 0); if (nw && nh) { const colWid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid); return Math.min(maxHeight, (docWid * nh) / nw); } const childHeight = NumCast(childLayoutDoc._height); - const panelHeight = childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin; + const panelHeight = this.childFitWidth(childLayoutDoc) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin; return Math.min(childHeight, maxHeight, panelHeight); } @@ -664,41 +666,35 @@ export class CollectionStackingView extends CollectionSubView 35; @computed get buttonMenu() { - const menuDoc: Doc = Cast(this.rootDoc.layout_headerButton, Doc, null); - // TODO:glr Allow support for multiple buttons - if (menuDoc) { - const width: number = NumCast(menuDoc._width, 30); - const height: number = NumCast(menuDoc._height, 30); - return ( -
- -
- ); - } + const menuDoc = DocCast(this.layoutDoc.layout_headerButton); + return !menuDoc ? null : ( +
+ +
+ ); } @computed get nativeWidth() { @@ -723,8 +719,8 @@ export class CollectionStackingView extends CollectionSubView {buttonMenu || noviceExplainer ? ( @@ -739,7 +735,7 @@ export class CollectionStackingView extends CollectionSubView (this._scroll = e.currentTarget.scrollTop))} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 9626f06ca..8896e2d61 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -17,15 +17,14 @@ import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes' import { Networking } from '../../Network'; import { DragManager, dropActionType } from '../../util/DragManager'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; -import { InteractionUtils } from '../../util/InteractionUtils'; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; import { undoBatch, UndoManager } from '../../util/UndoManager'; import { DocComponent } from '../DocComponent'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; +import { LoadingBox } from '../nodes/LoadingBox'; import { CollectionView, CollectionViewProps } from './CollectionView'; import React = require('react'); -import { LoadingBox } from '../nodes/LoadingBox'; export interface SubCollectionViewProps extends CollectionViewProps { isAnyChildContentActive: () => boolean; @@ -60,7 +59,8 @@ export function CollectionSubView(moreProps?: X) { return this.props.DataDoc instanceof Doc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) : this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template } - rootSelected = () => this.props.isSelected() || (this.rootDoc && this.props.rootSelected()); + // this returns whether either the collection is selected, or the template that it is part of is selected + rootSelected = () => this.props.isSelected() || this.props.rootSelected(); // The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc. // When a document has a DataDoc but it's not a template, then it contains its own rendering data, but needs to pass the DataDoc through @@ -100,7 +100,7 @@ export function CollectionSubView(moreProps?: X) { } else if (Cast(this.dataField, listSpec(Doc), null)) { // otherwise, if the collection data is a list, then use it. rawdocs = Cast(this.dataField, listSpec(Doc), null); - } else { + } else if (this.dataField) { // Finally, if it's not a doc or a list and the document is a template, we try to render the root doc. // For example, if an image doc is rendered with a slide template, the template will try to render the data field as a collection. // Since the data field is actually an image, we set the list of documents to the singleton of root document's proto which will be an image. @@ -217,18 +217,18 @@ export function CollectionSubView(moreProps?: X) { const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); if (movedDocs.length) { const canAdd = - (de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.rootDoc)) && (dropAction !== 'inSame' || docDragData.draggedDocuments.every(d => d.embedContainer === this.rootDoc)); - const moved = docDragData.moveDocument(movedDocs, this.rootDoc, canAdd ? this.addDocument : returnFalse); + (de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.Document)) && (dropAction !== 'inSame' || docDragData.draggedDocuments.every(d => d.embedContainer === this.Document)); + const moved = docDragData.moveDocument(movedDocs, this.Document, canAdd ? this.addDocument : returnFalse); added = canAdd || moved ? moved : undefined; } else if (addedDocs.length) { added = this.addDocument(addedDocs); } - if (!added && ScriptCast(this.rootDoc.dropConverter)) { - ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData }); + if (!added && ScriptCast(this.Document.dropConverter)) { + ScriptCast(this.Document.dropConverter)?.script.run({ dragData: docDragData }); added = addedDocs.length ? this.addDocument(addedDocs) : true; } } else { - ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData }); + ScriptCast(this.Document.dropConverter)?.script.run({ dragData: docDragData }); added = this.addDocument(docDragData.droppedDocuments); !added && alert('You cannot perform this move'); } @@ -238,7 +238,7 @@ export function CollectionSubView(moreProps?: X) { } else if (de.complete.annoDragData) { const dropCreator = de.complete.annoDragData.dropDocCreator; de.complete.annoDragData.dropDocCreator = () => { - const dropped = dropCreator(this.props.isAnnotationOverlay ? this.rootDoc : undefined); + const dropped = dropCreator(this.props.isAnnotationOverlay ? this.Document : undefined); this.addDocument(dropped); return dropped; }; diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index a8f5345b7..1cdd200e5 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -47,9 +47,9 @@ export class CollectionTimeView extends CollectionSubView() { getAnchor = (addAsAnnotation: boolean) => { const anchor = Docs.Create.HTMLMarkerDocument([], { title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any, - annotationOn: this.rootDoc, + annotationOn: this.Document, }); - PresBox.pinDocView(anchor, { pinData: { type_collection: true, pivot: true, filters: true } }, this.rootDoc); + PresBox.pinDocView(anchor, { pinData: { type_collection: true, pivot: true, filters: true } }, this.Document); if (addAsAnnotation) { // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 54332a7fd..b34598731 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -101,7 +101,7 @@ export class CollectionTreeView extends CollectionSubView this.rootDoc.layout_autoHeight, + () => this.layoutDoc.layout_autoHeight, auto => auto && this.computeHeight(), { fireImmediately: true } ); @@ -117,19 +117,19 @@ export class CollectionTreeView extends CollectionSubView { this.refList.delete(ref); - this.rootDoc.layout_autoHeight && this.computeHeight(); + this.layoutDoc.layout_autoHeight && this.computeHeight(); }; observeHeight = (ref: any) => { if (ref) { this.refList.add(ref); this.observer = new _global.ResizeObserver( action((entries: any) => { - if (this.rootDoc.layout_autoHeight && ref && this.refList.size && !SnappingManager.GetIsDragging()) { + if (this.layoutDoc.layout_autoHeight && ref && this.refList.size && !SnappingManager.GetIsDragging()) { this.computeHeight(); } }) ); - this.rootDoc.layout_autoHeight && this.computeHeight(); + this.layoutDoc.layout_autoHeight && this.computeHeight(); this.observer.observe(ref); } }; @@ -142,7 +142,7 @@ export class CollectionTreeView extends CollectionSubView sameTree || dragData.draggedDocuments.some(d => d.embedContainer === this.doc && this.childDocs.includes(d)); if (isAlreadyInTree() !== sameTree) { console.log('WHAAAT'); @@ -160,7 +160,7 @@ export class CollectionTreeView extends CollectionSubView !docs.includes(v)); - if ((doc instanceof Doc ? [doc] : doc).some(doc => SelectionManager.Views().some(dv => Doc.AreProtosEqual(dv.rootDoc, doc)))) SelectionManager.DeselectAll(); + if ((doc instanceof Doc ? [doc] : doc).some(doc => SelectionManager.Views().some(dv => Doc.AreProtosEqual(dv.Document, doc)))) SelectionManager.DeselectAll(); if (result.length !== value.length && doc instanceof Doc) { const ind = DocListCast(targetDataDoc[this.props.fieldKey]).indexOf(doc); const prev = ind && DocListCast(targetDataDoc[this.props.fieldKey])[ind - 1]; @@ -316,12 +316,12 @@ export class CollectionTreeView extends CollectionSubView {StrCast(this.rootDoc.layout_explainer)} ; + return !Doc.noviceMode || !this.layoutDoc.layout_explainer ? null :
{StrCast(this.layoutDoc.layout_explainer)}
; } return35 = () => 35; @computed get buttonMenu() { - const menuDoc = Cast(this.rootDoc.layout_headerButton, Doc, null); + const menuDoc = Cast(this.layoutDoc.layout_headerButton, Doc, null); // To create a multibutton menu add a CollectionLinearView return !menuDoc ? null : (
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 426ad2c2f..4f3c5b9a2 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -34,6 +34,7 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV import { CollectionView } from './CollectionView'; import './TabDocView.scss'; import React = require('react'); +import { Docs } from '../../documents/Documents'; const _global = (window /* browser */ || global) /* node */ as any; interface TabDocViewProps { @@ -259,7 +260,7 @@ export class TabDocView extends React.Component { return; } const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false, pinProps); - const pinDoc = anchorDoc?.type === DocumentType.CONFIG ? anchorDoc : Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc); + const pinDoc = anchorDoc?.type === DocumentType.CONFIG ? anchorDoc : Docs.Create.ConfigDocument({}); pinDoc.presentation_targetDoc = anchorDoc ?? doc; pinDoc.title = doc.title + ' - Slide'; pinDoc.data = new List(); // the children of the embedding's layout are the presentation slide children. the embedding's data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data @@ -271,7 +272,6 @@ export class TabDocView extends React.Component { pinDoc.treeView = ''; // not really needed, but makes key value pane look better pinDoc.treeView_RenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area pinDoc.treeView_HeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. - pinDoc.treeView_ChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. pinDoc.treeView_FieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field pinDoc.treeView_ExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view pinDoc.treeView_HideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 6e3f8e807..9de74b761 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -19,7 +19,6 @@ import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from '../../util/DragManager'; import { LinkManager } from '../../util/LinkManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; -import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; @@ -144,7 +143,7 @@ export class TreeView extends React.Component { return NumCast(this.props.treeViewParent.maxEmbedHeight, 200); } @computed get dataDoc() { - return this.props.document.treeView_ChildrenOnRoot ? this.doc : this.doc[DocData]; + return this.doc[DocData]; } @computed get layoutDoc() { return Doc.Layout(this.doc); @@ -333,7 +332,7 @@ export class TreeView extends React.Component { const before = pt[1] < rect.top + rect.height / 2; const inside = pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length); this._header.current!.className = 'treeView-header'; - if (!this.props.treeView.outlineMode || DragManager.DocDragData?.treeViewDoc === this.props.treeView.rootDoc) { + if (!this.props.treeView.outlineMode || DragManager.DocDragData?.treeViewDoc === this.props.treeView.Document) { if (inside) this._header.current!.className += ' treeView-header-inside'; else if (before) this._header.current!.className += ' treeView-header-above'; else if (!before) this._header.current!.className += ' treeView-header-below'; @@ -361,7 +360,7 @@ export class TreeView extends React.Component { _width: 1000, _height: 10, }); - Doc.GetProto(bullet).title = ComputedField.MakeFunction('self.text?.Text'); + Doc.GetProto(bullet).title = ComputedField.MakeFunction('this.text?.Text'); Doc.GetProto(bullet).data = new List([]); DocumentManager.Instance.AddViewRenderedCb(bullet, dv => dv.ComponentView?.setFocus?.()); @@ -838,7 +837,7 @@ export class TreeView extends React.Component { ? [openEmbedding, makeFolder] : this.doc._type_collection === CollectionViewType.Docking ? [] - : this.props.treeView.rootDoc === Doc.MyRecentlyClosed + : this.props.treeView.Document === Doc.MyRecentlyClosed ? [reopenDoc] : [openEmbedding, focusDoc]), ]; @@ -882,8 +881,8 @@ export class TreeView extends React.Component { maxWidth: props?.PanelWidth() || undefined, background: props?.styleProvider?.(doc, props, StyleProp.BackgroundColor), outline: SnappingManager.GetIsDragging() ? undefined: `solid ${highlightColor} ${highlightIndex}px`, - paddingLeft: NumCast(treeView.rootDoc.childXPadding, NumCast(treeView.props.childXPadding, Doc.IsComicStyle(doc)?20:0)), - paddingRight: NumCast(treeView.rootDoc.childXPadding, NumCast(treeView.props.childXPadding, Doc.IsComicStyle(doc)?20:0)), + paddingLeft: NumCast(treeView.Document.childXPadding, NumCast(treeView.props.childXPadding, Doc.IsComicStyle(doc)?20:0)), + paddingRight: NumCast(treeView.Document.childXPadding, NumCast(treeView.props.childXPadding, Doc.IsComicStyle(doc)?20:0)), paddingTop: treeView.props.childYPadding, paddingBottom: treeView.props.childYPadding, }}> diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 403fba67b..d6a738084 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -37,6 +37,7 @@ export interface PoolData { zIndex?: number; width?: number; height?: number; + autoDim?: number; // 1 for set to Panel dims, 0 for use width/height as entered backgroundColor?: string; color?: string; opacity?: number; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx index 856e195a3..38aeea152 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx @@ -8,7 +8,7 @@ import React = require('react'); import { CollectionFreeFormView } from './CollectionFreeFormView'; export interface CollectionFreeFormPannableContentsProps { - rootDoc: Doc; + Document: Doc; viewDefDivClick?: ScriptField; children?: React.ReactNode | undefined; transition?: string; @@ -20,7 +20,7 @@ export interface CollectionFreeFormPannableContentsProps { @observer export class CollectionFreeFormPannableContents extends React.Component { @computed get presPaths() { - return CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.pathLines(this.props.rootDoc) : null; + return CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.pathLines(this.props.Document) : null; } // rectangle highlight used when following trail/link to a region of a collection that isn't a document showViewport = (viewport: { panX: number; panY: number; width: number; height: number } | undefined) => diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7f8bde9b4..6babe3c8f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -134,7 +134,7 @@ export class CollectionFreeFormView extends CollectionSubView { CollectionFreeFormDocumentView.animFields.forEach(val => { - const findexed = Cast(doc[`${val.key}-indexed`], listSpec('number'), null); + const findexed = Cast(doc[`${val.key}_indexed`], listSpec('number'), null); findexed?.length <= timecode + 1 && findexed.push(undefined as any as number); }); CollectionFreeFormDocumentView.animStringFields.forEach(val => { - const findexed = Cast(doc[`${val}-indexed`], listSpec('string'), null); + const findexed = Cast(doc[`${val}_indexed`], listSpec('string'), null); findexed?.length <= timecode + 1 && findexed.push(undefined as any as string); }); CollectionFreeFormDocumentView.animDataFields(doc).forEach(val => { - const findexed = Cast(doc[`${val}-indexed`], listSpec(InkField), null); + const findexed = Cast(doc[`${val}_indexed`], listSpec(InkField), null); findexed?.length <= timecode + 1 && findexed.push(undefined as any); }); }); @@ -262,7 +263,7 @@ export class CollectionFreeFormView extends CollectionSubView newBox[field.key]); - CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[`${field.key}-indexed`]); + CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[`${field.key}_indexed`]); CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[field.key]); delete newBox.activeFrame; CollectionFreeFormDocumentView.animFields.forEach((field, i) => field.key !== 'opacity' && (newBox[field.key] = vals[i])); @@ -283,15 +284,15 @@ export class CollectionFreeFormView extends CollectionSubView { - options.docTransform = new Transform(-NumCast(this.rootDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.rootDoc[this.panYFieldKey]) + NumCast(anchor.y), 1); - const res = this.props.focus(this.rootDoc, options); + options.docTransform = new Transform(-NumCast(this.layoutDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.layoutDoc[this.panYFieldKey]) + NumCast(anchor.y), 1); + const res = this.props.focus(this.Document, options); options.docTransform = undefined; return res; }; focus = (anchor: Doc, options: DocFocusOptions) => { if (this._lightboxDoc) return; - if (anchor === this.rootDoc) { + if (anchor === this.Document) { if (options.willZoomCentered && options.zoomScale) { this.fitContentOnce(); options.didMove = true; @@ -300,7 +301,7 @@ export class CollectionFreeFormView extends CollectionSubView, props: Opt, property: string) => { let styleProp = this.props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1 - switch (property) { - case StyleProp.BackgroundColor: - const cluster = NumCast(doc?.layout_cluster); - if (this.Document._freeform_useClusters && doc?.type !== DocumentType.IMG) { - if (this._clusterSets.length <= cluster) { - setTimeout(() => doc && this.updateCluster(doc)); - } else { - // choose a cluster color from a palette - const colors = ['#da42429e', '#31ea318c', 'rgba(197, 87, 20, 0.55)', '#4a7ae2c4', 'rgba(216, 9, 255, 0.5)', '#ff7601', '#1dffff', 'yellow', 'rgba(27, 130, 49, 0.55)', 'rgba(0, 0, 0, 0.268)']; - styleProp = colors[cluster % colors.length]; - const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor); - // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document - set?.map(s => (styleProp = StrCast(s.backgroundColor))); + if (doc && this.childDocList?.includes(doc)) + switch (property) { + case StyleProp.BackgroundColor: + const cluster = NumCast(doc?.layout_cluster); + if (this.Document._freeform_useClusters && doc?.type !== DocumentType.IMG) { + if (this._clusterSets.length <= cluster) { + setTimeout(() => doc && this.updateCluster(doc)); + } else { + // choose a cluster color from a palette + const colors = ['#da42429e', '#31ea318c', 'rgba(197, 87, 20, 0.55)', '#4a7ae2c4', 'rgba(216, 9, 255, 0.5)', '#ff7601', '#1dffff', 'yellow', 'rgba(27, 130, 49, 0.55)', 'rgba(0, 0, 0, 0.268)']; + styleProp = colors[cluster % colors.length]; + const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor); + // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document + set?.map(s => (styleProp = StrCast(s.backgroundColor))); + } } - } - break; - case StyleProp.FillColor: - if (doc && this.Document._currentFrame !== undefined) { - return CollectionFreeFormDocumentView.getStringValues(doc, NumCast(this.Document._currentFrame))?.fillColor; - } - } + break; + case StyleProp.FillColor: + if (doc && this.Document._currentFrame !== undefined) { + return CollectionFreeFormDocumentView.getStringValues(doc, NumCast(this.Document._currentFrame))?.fillColor; + } + } return styleProp; }; @@ -623,7 +625,7 @@ export class CollectionFreeFormView extends CollectionSubView { - this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.rootDoc)); + this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.Document)); this._deleteList = []; this._batch?.end(); }; @@ -752,8 +754,8 @@ export class CollectionFreeFormView extends CollectionSubView { if (!this._deleteList.includes(intersect.inkView)) { this._deleteList.push(intersect.inkView); - SetActiveInkWidth(StrCast(intersect.inkView.rootDoc.stroke_width?.toString()) || '1'); - SetActiveInkColor(StrCast(intersect.inkView.rootDoc.color?.toString()) || 'black'); + SetActiveInkWidth(StrCast(intersect.inkView.Document.stroke_width?.toString()) || '1'); + SetActiveInkColor(StrCast(intersect.inkView.Document.color?.toString()) || 'black'); // create a new curve by appending all curves of the current segment together in order to render a single new stroke. if (!e.shiftKey) { this._eraserLock++; @@ -785,7 +787,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.Document._isGroup || this.Document[(this.props.viewField ?? '_') + 'freeform_noZoom']) return; + if (this.Document.isGroup || this.Document[(this.props.viewField ?? '_') + 'freeform_noZoom']) return; let deltaScale = deltaY > 0 ? 1 / 1.05 : 1.05; if (deltaScale < 0) deltaScale = -deltaScale; const [x, y] = this.screenToLocalXf.transformPoint(pointX, pointY); @@ -935,15 +937,15 @@ export class CollectionFreeFormView extends CollectionSubView 20) { deltaScale = 20 / invTransform.Scale; } - if (deltaScale < 1 && invTransform.Scale <= NumCast(this.rootDoc[this.scaleFieldKey + '_min'])) { + if (deltaScale < 1 && invTransform.Scale <= NumCast(this.Document[this.scaleFieldKey + '_min'])) { this.setPan(0, 0); return; } - if (deltaScale * invTransform.Scale > NumCast(this.rootDoc[this.scaleFieldKey + '_max'], Number.MAX_VALUE)) { - deltaScale = NumCast(this.rootDoc[this.scaleFieldKey + '_max'], 1) / invTransform.Scale; + if (deltaScale * invTransform.Scale > NumCast(this.Document[this.scaleFieldKey + '_max'], Number.MAX_VALUE)) { + deltaScale = NumCast(this.Document[this.scaleFieldKey + '_max'], 1) / invTransform.Scale; } - if (deltaScale * invTransform.Scale < NumCast(this.rootDoc[this.scaleFieldKey + '_min'], this.isAnnotationOverlay ? 1 : 0)) { - deltaScale = NumCast(this.rootDoc[this.scaleFieldKey + '_min'], 1) / invTransform.Scale; + if (deltaScale * invTransform.Scale < NumCast(this.Document[this.scaleFieldKey + '_min'], this.isAnnotationOverlay ? 1 : 0)) { + deltaScale = NumCast(this.Document[this.scaleFieldKey + '_min'], 1) / invTransform.Scale; } const localTransform = invTransform.scaleAbout(deltaScale, x, y); @@ -956,11 +958,11 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom + if (this.Document.isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom PresBox.Instance?.pauseAutoPres(); if (this.layoutDoc._Transform || this.props.Document.treeView_OutlineMode === TreeViewType.outline) return; e.stopPropagation(); - const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.rootDoc) + '_nativeHeight'], this.nativeHeight); + const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight); const scrollable = this.isAnnotationOverlay && NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling + 1e-4; switch ( !e.ctrlKey && !e.shiftKey && !e.metaKey && !e.altKey ?// @@ -1024,28 +1026,28 @@ export class CollectionFreeFormView extends CollectionSubView 2 && this.rootDoc.layout_scrollTop === undefined && NumCast(this.rootDoc._freeform_scale, minScale) === minScale) { + } else if (fitYscroll > 2 && this.layoutDoc.layout_scrollTop === undefined && NumCast(this.layoutDoc._freeform_scale, minScale) === minScale) { const maxPanY = minPanY + fitYscroll; const relTop = (panY - minPanY) / (maxPanY - minPanY); - setTimeout(() => (this.rootDoc.layout_scrollTop = relTop * maxScrollTop), 10); + setTimeout(() => (this.layoutDoc.layout_scrollTop = relTop * maxScrollTop), 10); newPanY = minPanY; } !this.Document._verticalScroll && (this.Document[this.panXFieldKey] = this.isAnnotationOverlay ? newPanX : panX); @@ -1055,8 +1057,8 @@ export class CollectionFreeFormView extends CollectionSubView { - const collectionDoc = this.props.docViewPath().lastElement().rootDoc; - if (collectionDoc?._type_collection !== CollectionViewType.Freeform || collectionDoc._freeform_ !== undefined) { + const collectionDoc = this.props.docViewPath().lastElement().Document; + if (collectionDoc?._type_collection !== CollectionViewType.Freeform) { this.setPan( NumCast(this.layoutDoc[this.panXFieldKey]) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale NumCast(this.layoutDoc[this.panYFieldKey]) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(), @@ -1104,7 +1106,7 @@ export class CollectionFreeFormView extends CollectionSubView { const docView = fieldProps.DocumentView?.(); - if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.rootDoc._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { + if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { e.stopPropagation?.(); const below = !e.altKey && e.key !== 'Tab'; const layout_fieldKey = StrCast(docView.LayoutFieldKey); - const newDoc = Doc.MakeCopy(docView.rootDoc, true); - const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)]; + const newDoc = Doc.MakeCopy(docView.Document, true); + const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)]; newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List([]) : undefined; - if (below) newDoc.y = NumCast(docView.rootDoc.y) + NumCast(docView.rootDoc._height) + 10; - else newDoc.x = NumCast(docView.rootDoc.x) + NumCast(docView.rootDoc._width) + 10; - if (layout_fieldKey !== 'layout' && docView.rootDoc[layout_fieldKey] instanceof Doc) { - newDoc[layout_fieldKey] = docView.rootDoc[layout_fieldKey]; + if (below) newDoc.y = NumCast(docView.Document.y) + NumCast(docView.Document._height) + 10; + else newDoc.x = NumCast(docView.Document.x) + NumCast(docView.Document._width) + 10; + if (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) { + newDoc[layout_fieldKey] = docView.Document[layout_fieldKey]; } Doc.GetProto(newDoc).text = undefined; FormattedTextBox.SelectOnLoad = newDoc[Id]; @@ -1228,7 +1230,7 @@ export class CollectionFreeFormView extends CollectionSubView { // create an anchor that saves information about the current state of the freeform view (pan, zoom, view type) - const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presentation_transition: 500, annotationOn: this.rootDoc }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document._isGroup, type_collection: true, filters: true } }, this.rootDoc); + const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presentation_transition: 500, annotationOn: this.Document }); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document.isGroup, type_collection: true, filters: true } }, this.Document); if (addAsAnnotation) { if (Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) { @@ -1434,7 +1437,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.Document._isGroup && this.childDocs.length === this.childDocList?.length) { + if (this.Document.isGroup && this.childDocs.length === this.childDocList?.length) { const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: NumCast(cd._width), height: NumCast(cd._height) })); return aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); } @@ -1481,7 +1484,7 @@ export class CollectionFreeFormView extends CollectionSubView this.isContentActive(), // if autoreset is on, then whenever the view is selected, it will be restored to it default pan/zoom positions - active => !SnappingManager.GetIsDragging() && this.rootDoc[this.autoResetFieldKey] && active && this.resetView() + active => !SnappingManager.GetIsDragging() && this.dataDoc[this.autoResetFieldKey] && active && this.resetView() ); }) ); @@ -1575,7 +1578,7 @@ export class CollectionFreeFormView extends CollectionSubView disposer?.()); } @@ -1616,9 +1619,9 @@ export class CollectionFreeFormView extends CollectionSubView { - this.rootDoc[this.panXFieldKey] = NumCast(this.rootDoc[this.panXFieldKey + '_reset']); - this.props.Document[this.panYFieldKey] = NumCast(this.rootDoc[this.panYFieldKey + '_reset']); - this.rootDoc[this.scaleFieldKey] = NumCast(this.rootDoc[this.scaleFieldKey + '_reset'], 1); + this.layoutDoc[this.panXFieldKey] = NumCast(this.dataDoc[this.panXFieldKey + '_reset']); + this.layoutDoc[this.panYFieldKey] = NumCast(this.dataDoc[this.panYFieldKey + '_reset']); + this.layoutDoc[this.scaleFieldKey] = NumCast(this.dataDoc[this.scaleFieldKey + '_reset'], 1); }; /// /// resetView restores a freeform collection to unit scale and centered at (0,0) UNLESS @@ -1626,11 +1629,11 @@ export class CollectionFreeFormView extends CollectionSubView { - this.rootDoc[this.autoResetFieldKey] = !this.rootDoc[this.autoResetFieldKey]; - if (this.rootDoc[this.autoResetFieldKey]) { - this.rootDoc[this.panXFieldKey + '_reset'] = this.rootDoc[this.panXFieldKey]; - this.rootDoc[this.panYFieldKey + '_reset'] = this.rootDoc[this.panYFieldKey]; - this.rootDoc[this.scaleFieldKey + '_reset'] = this.rootDoc[this.scaleFieldKey]; + this.dataDoc[this.autoResetFieldKey] = !this.dataDoc[this.autoResetFieldKey]; + if (this.dataDoc[this.autoResetFieldKey]) { + this.dataDoc[this.panXFieldKey + '_reset'] = this.dataDoc[this.panXFieldKey]; + this.dataDoc[this.panYFieldKey + '_reset'] = this.dataDoc[this.panYFieldKey]; + this.dataDoc[this.scaleFieldKey + '_reset'] = this.dataDoc[this.scaleFieldKey]; } }; @@ -1639,8 +1642,8 @@ export class CollectionFreeFormView extends CollectionSubView (Doc.UserDoc().defaultTextLayout = undefined), icon: 'eye' }); - appearanceItems.push({ description: `Pin View`, event: () => this.props.pinToPres(this.rootDoc, { pinViewport: MarqueeView.CurViewBounds(this.rootDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' }); + appearanceItems.push({ description: `Pin View`, event: () => this.props.pinToPres(this.Document, { pinViewport: MarqueeView.CurViewBounds(this.dataDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' }); !Doc.noviceMode && appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: 'compress-arrows-alt' }); this.props.renderDepth && appearanceItems.push({ description: 'Ungroup collection', event: this.promoteCollection, icon: 'table' }); - this.props.Document._isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: this.transcribeStrokes, icon: 'font' }); + this.props.Document.isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: this.transcribeStrokes, icon: 'font' }); !Doc.noviceMode ? appearanceItems.push({ description: 'Arrange contents in grid', event: this.layoutDocsInGrid, icon: 'table' }) : null; !Doc.noviceMode ? appearanceItems.push({ description: (this.Document._freeform_useClusters ? 'Hide' : 'Show') + ' Clusters', event: () => this.updateClusters(!this.Document._freeform_useClusters), icon: 'braille' }) : null; @@ -1681,7 +1684,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.props.Document._isGroup && this.props.Document.transcription) { + if (this.props.Document.isGroup && this.props.Document.transcription) { const text = StrCast(this.props.Document.transcription); const lines = text.split('\n'); const height = 30 + 15 * lines.length; @@ -1697,9 +1700,9 @@ export class CollectionFreeFormView extends CollectionSubView()) => { - if (visited.has(this.rootDoc)) return; - visited.add(this.rootDoc); - showGroupDragTarget && (this.GroupChildDrag = BoolCast(this.Document._isGroup)); + if (visited.has(this.Document)) return; + visited.add(this.Document); + showGroupDragTarget && (this.GroupChildDrag = BoolCast(this.Document.isGroup)); const activeDocs = this.getActiveDocuments(); const size = this.screenToLocalXf.transformDirection(this.props.PanelWidth(), this.props.PanelHeight()); const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] }; @@ -1708,14 +1711,14 @@ export class CollectionFreeFormView extends CollectionSubView doc.z === undefined && isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to activeDocs - .filter(doc => doc._isGroup && SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc)) + .filter(doc => doc.isGroup && SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc)) .forEach(doc => DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.dragStarting?.(snapToDraggedDoc, false, visited)); const horizLines: number[] = []; const vertLines: number[] = []; const invXf = this.screenToLocalXf.inverse(); snappableDocs - .filter(doc => !doc._isGroup && (snapToDraggedDoc || (SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc)))) + .filter(doc => !doc.isGroup && (snapToDraggedDoc || (SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc)))) .forEach(doc => { const { left, top, width, height } = docDims(doc); const topLeftInScreen = invXf.transformPoint(left, top); @@ -1783,7 +1786,7 @@ export class CollectionFreeFormView extends CollectionSubView 0 ? undefined : this.nudge} addDocTab={this.addDocTab} slowLoadDocuments={this.slowLoadDocuments} @@ -1828,7 +1831,7 @@ export class CollectionFreeFormView extends CollectionSubView this.nativeDimScaling; @@ -1849,7 +1852,7 @@ export class CollectionFreeFormView extends CollectionSubView Math.max(0, this.props.PanelHeight() - 30); lightboxScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-15, -15); onPassiveWheel = (e: WheelEvent) => { - const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.rootDoc) + '_nativeHeight'], this.nativeHeight); + const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight); const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling; this.props.isSelected() && !scrollable && e.preventDefault(); }; @@ -1930,14 +1933,14 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY dv && DocumentManager.Instance.showDocument(dv.rootDoc, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => { if (!focused) { - const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; + const selfFfview = !dv.Document.isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; let containers = dv.props.docViewPath(); let parFfview = dv.CollectionFreeFormView; for (var cont of containers) { parFfview = parFfview ?? cont.CollectionFreeFormView; } - while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView; - const ffview = selfFfview && selfFfview.rootDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview + while (parFfview?.Document.isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView; + const ffview = selfFfview && selfFfview.layoutDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview ffview?.zoomSmoothlyAboutPt(ffview.screenToLocalXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime); Doc.linkFollowHighlight(dv?.props.Document, false); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 2092ecb7a..18b9b4423 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -348,6 +348,7 @@ export class MarqueeView extends React.Component { Doc.GetProto(doc).data = new List(selected); + Doc.GetProto(doc).isGroup = makeGroup; Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform'; doc._freeform_panX = doc._freeform_panY = 0; return doc; @@ -355,7 +356,6 @@ export class MarqueeView extends React.Component this.props.isSelected() || this.props.isContentActive(); - isChildContentActive = () => (this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : undefined); + isChildContentActive = () => (this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.Document.childDocumentsActive)) ? true : undefined); /** * * @param layout @@ -187,6 +187,7 @@ export class CollectionGridView extends CollectionSubView() { return ( ); } diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index 4267a9059..a06ed3a2d 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -48,7 +48,7 @@ export class CollectionLinearView extends CollectionSubView() { componentDidMount() { this._widthDisposer = reaction( - () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearView_IsOpen ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (NumCast(doc._width) || this.dimension()) + tot + 4, 0) : 0), + () => 5 + NumCast(this.dataDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearView_IsOpen ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (NumCast(doc._width) || this.dimension()) + tot + 4, 0) : 0), width => this.childDocs.length && (this.layoutDoc._width = width), { fireImmediately: true } ); @@ -58,7 +58,7 @@ export class CollectionLinearView extends CollectionSubView() { if (ele) this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); }; - dimension = () => NumCast(this.rootDoc._height); + dimension = () => NumCast(this.layoutDoc._height); getTransform = (ele: Opt) => { if (!ele) return Transform.Identity(); const { scale, translateX, translateY } = Utils.GetScreenTransform(ele); @@ -183,7 +183,7 @@ export class CollectionLinearView extends CollectionSubView() { PanelWidth={doc[Width]} PanelHeight={nested || doc._height ? doc[Height] : this.dimension} renderDepth={this.props.renderDepth + 1} - dontRegisterView={BoolCast(this.rootDoc.childDontRegisterViews)} + dontRegisterView={BoolCast(this.Document.childDontRegisterViews)} focus={emptyFunction} styleProvider={this.props.styleProvider} docViewPath={returnEmptyDoclist} @@ -215,7 +215,7 @@ export class CollectionLinearView extends CollectionSubView() { toggleStatus={BoolCast(this.layoutDoc.linearView_IsOpen)} onClick={() => { this.layoutDoc.linearView_IsOpen = !isExpanded; - ScriptCast(this.rootDoc.onClick)?.script.run({ this: this.rootDoc }, console.log); + ScriptCast(this.Document.onClick)?.script.run({ this: this.Document }, console.log); }} tooltip={isExpanded ? 'Close' : 'Open'} fillWidth={true} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss index cb0d5e03f..4e2968933 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss @@ -17,7 +17,7 @@ } .contentFittingDocumentView { - width: unset; + margin: auto; } .label-wrapper { diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index c2586fb4b..05ec0448b 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -219,8 +219,8 @@ export class CollectionMulticolumnView extends CollectionSubView() { if (this.childDocs.includes(d)) { if (dropInd > this.childDocs.indexOf(d)) dropInd--; } - Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d); - Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1); + Doc.RemoveDocFromList(this.dataDoc, this.props.fieldKey, d); + Doc.AddDocToList(this.dataDoc, this.props.fieldKey, d, DocListCast(this.dataDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1); } }) ); @@ -235,18 +235,25 @@ export class CollectionMulticolumnView extends CollectionSubView() { isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive(); isChildContentActive = () => { - const childDocsActive = this.props.childDocumentsActive?.() ?? this.rootDoc.childDocumentsActive; + const childDocsActive = this.props.childDocumentsActive?.() ?? this.Document.childDocumentsActive; return this.props.isContentActive?.() === false || childDocsActive === false ? false // : this.props.isDocumentActive?.() && childDocsActive ? true : undefined; }; - getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number, shouldNotScale: () => boolean) => { + getDisplayDoc = (childLayout: Doc) => { + const width = () => this.lookupPixels(childLayout); + const height = () => this.props.PanelHeight() - 2 * NumCast(this.layoutDoc._yMargin) - (BoolCast(this.layoutDoc.showWidthLabels) ? 20 : 0); + const dxf = () => + this.lookupIndividualTransform(childLayout) + .translate(-NumCast(this.layoutDoc._xMargin), -NumCast(this.layoutDoc._yMargin)) + .scale(this.props.NativeDimScaling?.() || 1); + const shouldNotScale = () => this.props.fitContentsToBox?.() || BoolCast(childLayout.freeform_fitContentsToBox); return ( ); }; @@ -288,26 +296,15 @@ export class CollectionMulticolumnView extends CollectionSubView() { @computed private get contents(): JSX.Element[] | null { const { childLayoutPairs } = this; - const { Document, PanelHeight } = this.props; const collector: JSX.Element[] = []; for (let i = 0; i < childLayoutPairs.length; i++) { const { layout } = childLayoutPairs[i]; - const aspect = Doc.NativeAspect(layout, undefined, true); - const width = () => this.lookupPixels(layout); - const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); - const docwidth = () => (layout._layout_reflowHorizontal ? width() : Math.min(height() * aspect, width())); - const docheight = () => Math.min(docwidth() / aspect, height()); - const dxf = () => - this.lookupIndividualTransform(layout) - .translate(-NumCast(Document._xMargin) - (width() - docwidth()) / 2, -NumCast(Document._yMargin)) - .scale(this.props.NativeDimScaling?.() || 1); - const shouldNotScale = () => this.props.fitContentsToBox?.() || BoolCast(layout.freeform_fitContentsToBox); collector.push( -
- {this.getDisplayDoc(layout, dxf, docwidth, docheight, shouldNotScale)} +
+ {this.getDisplayDoc(layout)}
, this.childDocs.indexOf(d)) dropInd--; } - Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d); - Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1); + Doc.RemoveDocFromList(this.dataDoc, this.props.fieldKey, d); + Doc.AddDocToList(this.dataDoc, this.props.fieldKey, d, DocListCast(this.dataDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1); } }) ); @@ -231,14 +231,21 @@ export class CollectionMultirowView extends CollectionSubView() { isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive(); isChildContentActive = () => { - const childDocsActive = this.props.childDocumentsActive?.() ?? this.rootDoc.childDocumentsActive; + const childDocsActive = this.props.childDocumentsActive?.() ?? this.Document.childDocumentsActive; return this.props.isContentActive?.() === false || childDocsActive === false ? false // : this.props.isDocumentActive?.() && childDocsActive ? true : undefined; }; - getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number, shouldNotScale: () => boolean) => { + getDisplayDoc = (layout: Doc) => { + const height = () => this.lookupPixels(layout); + const width = () => this.props.PanelWidth() - 2 * NumCast(this.layoutDoc._xMargin) - (BoolCast(this.layoutDoc.showWidthLabels) ? 20 : 0); + const dxf = () => + this.lookupIndividualTransform(layout) + .translate(-NumCast(this.layoutDoc._xMargin), -NumCast(this.layoutDoc._yMargin)) + .scale(this.props.NativeDimScaling?.() || 1); + const shouldNotScale = () => this.props.fitContentsToBox?.() || BoolCast(layout.freeform_fitContentsToBox); return ( ); }; @@ -284,24 +292,13 @@ export class CollectionMultirowView extends CollectionSubView() { @computed private get contents(): JSX.Element[] | null { const { childLayoutPairs } = this; - const { Document, PanelWidth } = this.props; const collector: JSX.Element[] = []; for (let i = 0; i < childLayoutPairs.length; i++) { const { layout } = childLayoutPairs[i]; - const aspect = Doc.NativeAspect(layout, undefined, true); - const height = () => this.lookupPixels(layout); - const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); - const docheight = () => Math.min(width() / aspect, height()); - const docwidth = () => (layout._layout_reflowHorizontal ? width() : Math.min(width(), docheight() * aspect)); - const dxf = () => - this.lookupIndividualTransform(layout) - .translate(-NumCast(Document._xMargin) - (width() - docwidth()) / 2, -NumCast(Document._yMargin) - (height() - docheight()) / 2) - .scale(this.props.NativeDimScaling?.() || 1); - const shouldNotScale = () => this.props.fitContentsToBox?.() || BoolCast(layout.freeform_fitContentsToBox); collector.push( -
- {this.getDisplayDoc(layout, dxf, docwidth, docheight, shouldNotScale)} - +
+ {this.getDisplayDoc(layout)} +
, Doc.AreProtosEqual(DocCast(doc.embedContainer), this.rootDoc)); + const selected = SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.Document)); if (!selected.length) { for (const sel of SelectionManager.Docs()) { const contextPath = DocumentManager.GetContextPath(sel, true); - if (contextPath.includes(this.rootDoc)) { - const parentInd = contextPath.indexOf(this.rootDoc); + if (contextPath.includes(this.Document)) { + const parentInd = contextPath.indexOf(this.Document); return parentInd < contextPath.length - 1 ? [contextPath[parentInd + 1]] : []; } } @@ -146,7 +146,7 @@ export class CollectionSchemaView extends CollectionSubView() { Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1])); this._keysDisposer = observe( - this.rootDoc[this.fieldKey ?? 'data'] as List, + this.dataDoc[this.fieldKey ?? 'data'] as List, change => { switch (change.type as any) { case 'splice': @@ -154,7 +154,7 @@ export class CollectionSchemaView extends CollectionSubView() { (change as any).added.forEach((doc: Doc) => // for each document added Doc.GetAllPrototypes(doc.value as Doc).forEach(proto => // for all of its prototypes (and itself) Object.keys(proto).forEach(action(key => // check if any of its keys are new, and add them - !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo('')))))); + !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo(key, key === 'author')))))); break; case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list } diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 9d5b533d1..2c251d3cf 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -102,7 +102,7 @@ export class SchemaTableCell extends React.Component { } @computed get defaultCellContent() { - const { color, textDecoration, fieldProps } = SchemaTableCell.renderProps(this.props); + const { color, textDecoration, fieldProps, pointerEvents } = SchemaTableCell.renderProps(this.props); return (
{ color, textDecoration, width: '100%', + pointerEvents, }}> - [ where, { checkResult: () =>(editorView ? (where === 'vcent' ? SelectionManager.Docs().some(doc => doc.layout_centered): + [ where, { checkResult: () =>(editorView ? (where === 'vcent' ? RichTextMenu.Instance.textVcenter: (RichTextMenu.Instance.textAlign === where)): - where === 'vcent' ? BoolCast(Doc.UserDoc().layout_centered): + where === 'vcent' ? BoolCast(Doc.UserDoc()._layout_centered): (Doc.UserDoc().textAlign ===where) ? true:false), - toggle: () => (editorView?.state ? (where === 'vcent' ? SelectionManager.Docs().forEach(doc => doc.layout_centered = !doc.layout_centered): + toggle: () => (editorView?.state ? (where === 'vcent' ? RichTextMenu.Instance.vcenterToggle(editorView, editorView.dispatch): RichTextMenu.Instance.align(editorView, editorView.dispatch, where)): - where === 'vcent' ? Doc.UserDoc().layout_centered = !Doc.UserDoc().layout_centered: + where === 'vcent' ? Doc.UserDoc()._layout_centered = !Doc.UserDoc()._layout_centered: (Doc.UserDoc().textAlign = where))}]); // prettier-ignore // prettier-ignore const listings:attrfuncs[] = (['bullet','decimal'] as attrname[]).map(list => diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 8d80f1364..807a77233 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -366,8 +366,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.Transition; // prettier-ignore w_DataTransition = () => this.DataTransition; // prettier-ignore - PanelWidth = () => this.Width > 0 ? this.Width : this.props.PanelWidth?.(); // prettier-ignore - PanelHeight = () => this.Height > 0 ? this.Height : this.props.PanelHeight?.(); // prettier-ignore + PanelWidth = () => this.props.autoDim ? this.props.PanelWidth?.() : this.Width; // prettier-ignore + PanelHeight = () => this.props.autoDim ? this.props.PanelHeight?.() : this.Height; // prettier-ignore @action componentDidUpdate() { this.WrapperKeys.forEach(keys => ((this as any)[keys.upper] = (this.props as any)[keys.lower])); @@ -113,7 +115,7 @@ export interface CollectionFreeFormDocumentViewProps { @observer export class CollectionFreeFormDocumentView extends DocComponent() { get displayName() { // this makes mobx trace() statements more descriptive - return 'CollectionFreeFormDocumentView(' + this.rootDoc.title + ')'; + return 'CollectionFreeFormDocumentView(' + this.Document.title + ')'; } // prettier-ignore public static animFields: { key: string; val?: number }[] = [ { key: 'x' }, @@ -148,14 +150,14 @@ export class CollectionFreeFormDocumentView extends DocComponent { - p[val.key] = Cast(doc[`${val.key}-indexed`], listSpec('number'), fillIn ? [NumCast(doc[val.key], val.val)] : []).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as number); + p[val.key] = Cast(doc[`${val.key}_indexed`], listSpec('number'), fillIn ? [NumCast(doc[val.key], val.val)] : []).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as number); return p; }, {} as { [val: string]: Opt }); } public static getStringValues(doc: Doc, time: number) { return CollectionFreeFormDocumentView.animStringFields.reduce((p, val) => { - p[val] = Cast(doc[`${val}-indexed`], listSpec('string'), [StrCast(doc[val])]).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as string); + p[val] = Cast(doc[`${val}_indexed`], listSpec('string'), [StrCast(doc[val])]).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as string); return p; }, {} as { [val: string]: Opt }); } @@ -163,40 +165,52 @@ export class CollectionFreeFormDocumentView extends DocComponent }) { const timecode = Math.round(time); Object.keys(vals).forEach(val => { - const findexed = Cast(d[`${val}-indexed`], listSpec('string'), []).slice(); + const findexed = Cast(d[`${val}_indexed`], listSpec('string'), []).slice(); findexed[timecode] = vals[val] as any as string; - d[`${val}-indexed`] = new List(findexed); + d[`${val}_indexed`] = new List(findexed); }); } public static setValues(time: number, d: Doc, vals: { [val: string]: Opt }) { const timecode = Math.round(time); Object.keys(vals).forEach(val => { - const findexed = Cast(d[`${val}-indexed`], listSpec('number'), []).slice(); + const findexed = Cast(d[`${val}_indexed`], listSpec('number'), []).slice(); findexed[timecode] = vals[val] as any as number; - d[`${val}-indexed`] = new List(findexed); + d[`${val}_indexed`] = new List(findexed); }); } + public static gotoKeyFrame(doc: Doc, newFrame: number) { + if (doc) { + const childDocs = DocListCast(doc[Doc.LayoutFieldKey(doc)]); + const currentFrame = Cast(doc._currentFrame, 'number', null); + if (currentFrame === undefined) { + doc._currentFrame = 0; + CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0); + } + CollectionFreeFormView.updateKeyframe(undefined, [...childDocs, doc], currentFrame || 0); + doc._currentFrame = newFrame === undefined ? 0 : Math.max(0, newFrame); + } + } public static setupKeyframes(docs: Doc[], currTimecode: number, makeAppear: boolean = false) { docs.forEach(doc => { if (doc.appearFrame === undefined) doc.appearFrame = currTimecode; - if (!doc['opacity-indexed']) { + if (!doc['opacity_indexed']) { // opacity is unlike other fields because it's value should not be undefined before it appears to enable it to fade-in - doc['opacity-indexed'] = new List(numberRange(currTimecode + 1).map(t => (!doc.z && makeAppear && t < NumCast(doc.appearFrame) ? 0 : 1))); + doc['opacity_indexed'] = new List(numberRange(currTimecode + 1).map(t => (!doc.z && makeAppear && t < NumCast(doc.appearFrame) ? 0 : 1))); } CollectionFreeFormDocumentView.animFields.forEach(val => (doc[val.key] = ComputedField.MakeInterpolatedNumber(val.key, 'activeFrame', doc, currTimecode, val.val))); CollectionFreeFormDocumentView.animStringFields.forEach(val => (doc[val] = ComputedField.MakeInterpolatedString(val, 'activeFrame', doc, currTimecode))); CollectionFreeFormDocumentView.animDataFields(doc).forEach(val => (doc[val] = ComputedField.MakeInterpolatedDataField(val, 'activeFrame', doc, currTimecode))); const targetDoc = doc; // data fields, like rtf 'text' exist on the data doc, so //doc !== targetDoc && (targetDoc.embedContainer = doc.embedContainer); // the computed fields don't see the layout doc -- need to copy the embedContainer to the data doc (HACK!!!) and set the activeFrame on the data doc (HACK!!!) - targetDoc.activeFrame = ComputedField.MakeFunction('self.embedContainer?._currentFrame||0'); + targetDoc.activeFrame = ComputedField.MakeFunction('this.embedContainer?._currentFrame||0'); targetDoc.dataTransition = 'inherit'; }); } @action public float = () => { - const topDoc = this.rootDoc; + const topDoc = this.Document; const containerDocView = this.props.docViewPath().lastElement(); const screenXf = containerDocView?.screenToLocalTransform(); if (screenXf) { @@ -238,7 +252,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { if (this.CollectionFreeFormView.isAnyChildContentActive()) return undefined; - const isGroup = this.rootDoc._isGroup && (!this.rootDoc.backgroundColor || this.rootDoc.backgroundColor === 'transparent'); + const isGroup = this.Document.isGroup && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent'); return isGroup ? (this.props.isDocumentActive?.() ? 'group' : this.props.isGroupActive?.() ? 'child' : 'inactive') : this.props.isGroupActive?.() ? 'child' : undefined; }; public static CollectionFreeFormDocViewClassName = 'collectionFreeFormDocumentView-container'; @@ -265,3 +279,6 @@ export class CollectionFreeFormDocumentView extends DocComponent { click = (e: React.MouseEvent) => { const clickScript = (this.props as any).onClick as Opt; - clickScript?.script.run({ this: this.props.Document, self: this.props.RootDoc, scale: this.props.scaling }); + clickScript?.script.run({ this: this.props.Document, self: this.props.Document, scale: this.props.scaling }); }; onInput = (e: React.FormEvent) => { const onInputScript = (this.props as any).onInput as Opt; - onInputScript?.script.run({ this: this.props.Document, self: this.props.RootDoc, value: (e.target as any).textContent }); + onInputScript?.script.run({ this: this.props.Document, self: this.props.Document, value: (e.target as any).textContent }); }; render() { const style: { [key: string]: any } = {}; - const divKeys = OmitKeys(this.props, ['children', 'dragStarting', 'dragEnding', 'htmltag', 'RootDoc', 'scaling', 'Document', 'key', 'onInput', 'onClick', '__proto__']).omit; + const divKeys = OmitKeys(this.props, ['children', 'dragStarting', 'dragEnding', 'htmltag', 'scaling', 'Document', 'key', 'onInput', 'onClick', '__proto__']).omit; const replacer = (match: any, expr: string, offset: any, string: any) => { - // bcz: this executes a script to convert a propery expression string: { script } into a value - return (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: 'number' })?.script.run({ self: this.props.RootDoc, this: this.props.Document, scale: this.props.scaling }).result as string) || ''; + // bcz: this executes a script to convert a property expression string: { script } into a value + return (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: 'number' })?.script.run({ self: this.props.Document, this: this.props.Document, scale: this.props.scaling }).result as string) || ''; }; Object.keys(divKeys).map((prop: string) => { const p = (this.props as any)[prop] as string; @@ -119,9 +118,6 @@ export class HTMLtag extends React.Component { @observer export class DocumentContentsView extends React.Component< DocumentViewProps & { - isSelected: () => boolean; - select: (ctrl: boolean) => void; - NativeDimScaling?: () => number; setHeight?: (height: number) => void; layout_fieldKey: string; } @@ -137,6 +133,10 @@ export class DocumentContentsView extends React.Component< return '

Loading layout

'; } + componentDidUpdate(prevProps: Readonly void) | undefined; layout_fieldKey: string }>, prevState: Readonly<{}>, snapshot?: any): void { + Object.keys(prevProps).forEach(pkey => (prevProps as any)[pkey] !== (this.props as any)[pkey] && console.log(pkey + ' ' + (prevProps as any)[pkey] + ' ' + (this.props as any)[pkey])); + } + get dataDoc() { const proto = this.props.DataDoc || Doc.GetProto(this.props.Document); return proto instanceof Promise ? undefined : proto; @@ -170,7 +170,6 @@ export class DocumentContentsView extends React.Component< ]; const list = { ...OmitKeys(this.props, [...docOnlyProps], '').omit, - RootDoc: Cast(this.layoutDoc?.rootDocument, Doc, null) || this.layoutDoc, Document: this.layoutDoc, DataDoc: this.dataDoc, onClick: onClick, @@ -195,7 +194,7 @@ export class DocumentContentsView extends React.Component< // replace HTML with corresponding HTML tag as in: becomes const replacer2 = (match: any, p1: string, offset: any, string: any) => { - return `; + return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.ShowTitle) as Opt; } @computed get NativeDimScaling() { return this.props.NativeDimScaling?.() || 1; @@ -302,13 +302,13 @@ export class DocumentViewInternal extends DocComponent dv.docView?._mainCont.current); - const selected = views.length > 1 && views.some(dv => dv.rootDoc === this.Document) ? views : [this.props.DocumentView()]; - const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.rootDoc)); + const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this.props.DocumentView()]; + const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.Document)); const [left, top] = this.props.ScreenToLocalTransform().scale(this.NativeDimScaling).inverse().transformPoint(0, 0); dragData.offset = this.props .ScreenToLocalTransform() @@ -417,7 +417,7 @@ export class DocumentViewInternal extends DocComponent dv.docView!._mainCont.current!), dragData, @@ -430,8 +430,8 @@ export class DocumentViewInternal extends DocComponent { const targetMatch = - Doc.AreProtosEqual(anchor, this.rootDoc) || // anchor is this document, so anchor's properties apply to this document - (DocCast(anchor)?.layout_unrendered && Doc.AreProtosEqual(DocCast(anchor.annotationOn), this.rootDoc)) // the anchor is an layout_unrendered annotation on this document, so anchor properties apply to this document + Doc.AreProtosEqual(anchor, this.Document) || // anchor is this document, so anchor's properties apply to this document + (DocCast(anchor)?.layout_unrendered && Doc.AreProtosEqual(DocCast(anchor.annotationOn), this.Document)) // the anchor is an layout_unrendered annotation on this document, so anchor properties apply to this document ? true : false; return targetMatch && PresBox.restoreTargetDocView(docView, anchor, focusSpeed) ? focusSpeed : undefined; @@ -450,23 +450,22 @@ export class DocumentViewInternal extends DocComponent= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) { let stopPropagate = true; let preventDefault = true; - !this.rootDoc._keepZWhenDragged && this.props.bringToFront(this.rootDoc); + !this.layoutDoc._keepZWhenDragged && this.props.bringToFront(this.Document); if (this._doubleTap) { const defaultDblclick = this.props.defaultDoubleClick?.() || this.Document.defaultDoubleClick; if (this.onDoubleClickHandler?.script) { const { clientX, clientY, shiftKey, altKey, ctrlKey } = e; // or we could call e.persist() to capture variables // prettier-ignore const func = () => this.onDoubleClickHandler.script.run( { - this: this.layoutDoc, - self: this.rootDoc, + this: this.Document, scriptContext: this.props.scriptContext, documentView: this.props.DocumentView(), clientX, clientY, altKey, shiftKey, ctrlKey, value: undefined, }, console.log ); UndoManager.RunInBatch(() => (func().result?.select === true ? this.props.select(false) : ''), 'on double click'); - } else if (!Doc.IsSystem(this.rootDoc) && (defaultDblclick === undefined || defaultDblclick === 'default')) { - UndoManager.RunInBatch(() => LightboxView.Instance.AddDocTab(this.rootDoc, OpenWhere.lightbox), 'double tap'); + } else if (!Doc.IsSystem(this.Document) && (defaultDblclick === undefined || defaultDblclick === 'default')) { + UndoManager.RunInBatch(() => LightboxView.Instance.AddDocTab(this.Document, OpenWhere.lightbox), 'double tap'); SelectionManager.DeselectAll(); Doc.UnBrushDoc(this.props.Document); } else { @@ -488,8 +487,7 @@ export class DocumentViewInternal extends DocComponent UndoManager.RunInBatch(func, 'click ' + this.rootDoc.title); + clickFunc = () => UndoManager.RunInBatch(func, 'click ' + this.Document.title); } else { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) { @@ -516,7 +514,7 @@ export class DocumentViewInternal extends DocComponent (sendToBack ? this.props.DocumentView().props.bringToFront(this.rootDoc, true) : + clickFunc ?? (() => (sendToBack ? this.props.DocumentView().props.bringToFront(this.Document, true) : this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this.props.select(e.ctrlKey||e.shiftKey, e.metaKey))); const waitFordblclick = this.props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick; @@ -538,7 +536,7 @@ export class DocumentViewInternal extends DocComponent { if (DocumentView.LongPress) { - if (this.rootDoc.undoIgnoreFields) { + if (this.Document.undoIgnoreFields) { runInAction(() => (UndoStack.HideInline = !UndoStack.HideInline)); } else { this.props.select(false); @@ -563,10 +561,10 @@ export class DocumentViewInternal extends DocComponent { - const hadOnClick = this.rootDoc.onClick; + const hadOnClick = this.Document.onClick; this.noOnClick(); this.Document.onClick = hadOnClick ? undefined : FollowLinkScript(); this.Document.waitForDoubleClickToClick = hadOnClick ? undefined : 'never'; @@ -653,11 +651,11 @@ export class DocumentViewInternal extends DocComponent { - if (e && this.rootDoc._layout_hideContextMenu && Doc.noviceMode) { + if (e && this.layoutDoc._layout_hideContextMenu && Doc.noviceMode) { e.preventDefault(); e.stopPropagation(); //!this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false); @@ -738,7 +736,7 @@ export class DocumentViewInternal extends DocComponent { - if (this.rootDoc.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this.props.isSelected() && SelectionManager.SelectView(this.props.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. + if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this.props.isSelected() && SelectionManager.SelectView(this.props.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. setTimeout(() => simulateMouseClick(document.elementFromPoint(e.clientX, e.clientY), e.clientX, e.clientY, e.screenX, e.screenY)); }; if (navigator.userAgent.includes('Macintosh')) { @@ -751,11 +749,9 @@ export class DocumentViewInternal extends DocComponent - cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.layoutDoc, scriptContext: this.props.scriptContext, self: this.rootDoc }), icon: 'sticky-note' }) + cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.Document, scriptContext: this.props.scriptContext }), icon: 'sticky-note' }) ); - this.props - .contextMenuItems?.() - .forEach(item => item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.layoutDoc, scriptContext: this.props.scriptContext, self: this.rootDoc }), icon: item.icon as IconProp })); + this.props.contextMenuItems?.().forEach(item => item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.Document, scriptContext: this.props.scriptContext }), icon: item.icon as IconProp })); if (!this.props.Document.isFolder) { const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layout_fieldKey)], Doc, null); @@ -765,22 +761,22 @@ export class DocumentViewInternal extends DocComponent LightboxView.Instance.SetLightboxDoc(this.rootDoc), icon: 'external-link-alt' }); } - this.rootDoc.type === DocumentType.PRES && appearanceItems.push({ description: 'Pin', event: () => this.props.pinToPres(this.rootDoc, {}), icon: 'eye' }); + this.Document.type === DocumentType.PRES && appearanceItems.push({ description: 'Pin', event: () => this.props.pinToPres(this.rootDoc, {}), icon: 'eye' }); !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); !appearance && appearanceItems.length && cm.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'compass' }); - if (!Doc.IsSystem(this.rootDoc) && this.rootDoc.type !== DocumentType.PRES && ![CollectionViewType.Docking, CollectionViewType.Tree].includes(this.rootDoc._type_collection as any)) { + if (!Doc.IsSystem(this.Document) && this.Document.type !== DocumentType.PRES && ![CollectionViewType.Docking, CollectionViewType.Tree].includes(this.Document._type_collection as any)) { const existingOnClick = cm.findByDescription('OnClick...'); const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; if (this.props.bringToFront !== emptyFunction) { const zorders = cm.findByDescription('ZOrder...'); const zorderItems: ContextMenuProps[] = zorders && 'subitems' in zorders ? zorders.subitems : []; - zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: 'arrow-up' }); - zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: 'arrow-down' }); + zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.Document, false)), icon: 'arrow-up' }); + zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.Document, true)), icon: 'arrow-down' }); zorderItems.push({ - description: !this.rootDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged', - event: undoBatch(action(() => (this.rootDoc._keepZWhenDragged = !this.rootDoc._keepZWhenDragged))), + description: !this.layoutDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged', + event: undoBatch(action(() => (this.layoutDoc._keepZWhenDragged = !this.layoutDoc._keepZWhenDragged))), icon: 'hand-point-up', }); !zorders && cm.addItem({ description: 'Z Order...', addDivider: true, noexpand: true, subitems: zorderItems, icon: 'layer-group' }); @@ -816,7 +812,7 @@ export class DocumentViewInternal extends DocComponent Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: 'concierge-bell' }); moreItems.push({ description: `${this.Document._chromeHidden ? 'Show' : 'Hide'} Chrome`, event: () => (this.Document._chromeHidden = !this.Document._chromeHidden), icon: 'project-diagram' }); @@ -833,9 +829,9 @@ export class DocumentViewInternal extends DocComponent Doc.Zip(this.props.Document) }); - (this.rootDoc._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' }); + (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' }); if (this.props.removeDocument && Doc.ActiveDashboard !== this.props.Document) { // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions) constantItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' }); @@ -847,8 +843,8 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'keyboard' }); - !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.props.Document), icon: 'hand-point-right' }); - !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.props.Document[DocData]), icon: 'hand-point-right' }); + !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.Document), icon: 'hand-point-right' }); + !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.dataDoc), icon: 'hand-point-right' }); let documentationDescription: string | undefined = undefined; let documentationLink: string | undefined = undefined; @@ -902,7 +898,7 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; panelHeight = () => this.props.PanelHeight() - this.headerMargin; @@ -931,7 +927,7 @@ export class DocumentViewInternal extends DocComponent - (link.link_matchEmbeddings ? link.link_anchor_1 === this.rootDoc : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.rootDoc)) || - (link.link_matchEmbeddings ? link.link_anchor_2 === this.rootDoc : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.rootDoc)) || - ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.rootDoc)) || - ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.rootDoc)) + (link.link_matchEmbeddings ? link.link_anchor_1 === this.Document : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.Document)) || + (link.link_matchEmbeddings ? link.link_anchor_2 === this.Document : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.Document)) || + ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.Document)) || + ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.Document)) ); } @computed get allLinks() { TraceMobx(); - return LinkManager.Instance.getAllRelatedLinks(this.rootDoc); + return LinkManager.Instance.getAllRelatedLinks(this.Document); } hideLink = computedFn((link: Doc) => () => (link.link_displayLine = false)); @computed get allLinkEndpoints() { @@ -1020,7 +1015,7 @@ export class DocumentViewInternal extends DocComponent
)); @@ -1143,7 +1138,7 @@ export class DocumentViewInternal extends DocComponent @@ -1191,8 +1186,8 @@ export class DocumentViewInternal extends DocComponent { - if (this.rootDoc.layout_showTitle) { - this.rootDoc._layout_showTitle = field; + if (this.layoutDoc.layout_showTitle) { + this.layoutDoc._layout_showTitle = field; } else if (!this.props.layout_showTitle) { Doc.UserDoc().layout_showTitle = field; } @@ -1216,11 +1211,11 @@ export class DocumentViewInternal extends DocComponent (showTitle.split(';').length !== 1 ? '#' + showTitle : Field.toKeyValueString(this.rootDoc, showTitle.split(';')[0]))} + GetValue={() => (showTitle.split(';').length !== 1 ? '#' + showTitle : Field.toKeyValueString(this.Document, showTitle.split(';')[0]))} SetValue={undoBatch((input: string) => { if (input?.startsWith('#')) { - if (this.rootDoc.layout_showTitle) { - this.rootDoc._layout_showTitle = input?.substring(1); + if (this.layoutDoc.layout_showTitle) { + this.layoutDoc._layout_showTitle = input?.substring(1); } else if (!this.props.layout_showTitle) { Doc.UserDoc().layout_showTitle = input?.substring(1) ?? 'author_date'; } @@ -1246,7 +1241,7 @@ export class DocumentViewInternal extends DocComponent { TraceMobx(); - return !DocCast(this.Document) || GetEffectiveAcl(this.Document[DocData]) === AclPrivate + return !DocCast(this.Document) || GetEffectiveAcl(this.dataDoc) === AclPrivate ? null : this.docContents ?? (
<> - {this._componentView instanceof KeyValueBox ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.rootDoc[Animation], this.rootDoc)} + {this._componentView instanceof KeyValueBox ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} {borderPath?.jsx}
@@ -1377,7 +1372,7 @@ export class DocumentView extends React.Component { private _disposers: { [name: string]: IReactionDisposer } = {}; public clearViewTransition = () => { this.ViewTimer && clearTimeout(this.ViewTimer); - this.rootDoc._viewTransition = undefined; + this.layoutDoc._viewTransition = undefined; }; public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this.docView?.startDragging(x, y, dropAction, hideSource); @@ -1385,15 +1380,15 @@ export class DocumentView extends React.Component { public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => { this.AnimEffectTimer && clearTimeout(this.AnimEffectTimer); - this.rootDoc[Animation] = presEffect; - this.AnimEffectTimer = setTimeout(() => (this.rootDoc[Animation] = undefined), timeInMs); + this.Document[Animation] = presEffect; + this.AnimEffectTimer = setTimeout(() => (this.Document[Animation] = undefined), timeInMs); }; public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => { - this.rootDoc._viewTransition = `${transProp} ${timeInMs}ms`; + this.layoutDoc._viewTransition = `${transProp} ${timeInMs}ms`; if (dataTrans) this.rootDoc._dataTransition = `${transProp} ${timeInMs}ms`; this.ViewTimer && clearTimeout(this.ViewTimer); return (this.ViewTimer = setTimeout(() => { - this.rootDoc._viewTransition = undefined; + this.layoutDoc._viewTransition = undefined; this.rootDoc._dataTransition = 'inherit'; afterTrans?.(); }, timeInMs + 10)); @@ -1421,7 +1416,7 @@ export class DocumentView extends React.Component { DocServer.GetRefField(docId).then(docx => LightboxView.Instance.SetLightboxDoc( (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection - Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(self, self.target)') }, docId) + Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId) ) ); } @@ -1445,16 +1440,16 @@ export class DocumentView extends React.Component { return this.docView?._componentView; } get allLinks() { - return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.rootDoc || link.link_anchor_2 === this.rootDoc); + return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.rootDoc); } get LayoutFieldKey() { return this.docView?.LayoutFieldKey || 'layout'; } @computed get layout_fitWidth() { - return this.docView?._componentView?.layout_fitWidth?.() ?? this.props.layout_fitWidth?.(this.rootDoc) ?? this.layoutDoc?.layout_fitWidth; + return this.docView?._componentView?.layout_fitWidth?.() ?? this.props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth; } @computed get anchorViewDoc() { - return this.props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.rootDoc['link_anchor_2']) : this.props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.rootDoc['link_anchor_1']) : undefined; + return this.props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this.props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined; } @computed get hideLinkButton() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkBtn + (this.isSelected() ? ':selected' : '')); @@ -1526,7 +1521,7 @@ export class DocumentView extends React.Component { return this.props.CollectionFreeFormDocumentView?.(); } - public toggleNativeDimensions = () => this.docView && this.rootDoc.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight()); + public toggleNativeDimensions = () => this.docView && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight()); public getBounds = () => { if (!this.docView?.ContentDiv || this.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { return undefined; @@ -1560,7 +1555,7 @@ export class DocumentView extends React.Component { const deiconifyLayout = Cast(this.Document.deiconifyLayout, 'string', null); this.switchViews(deiconifyLayout ? true : false, deiconifyLayout, finalFinished); this.Document.deiconifyLayout = undefined; - this.props.bringToFront(this.rootDoc); + this.props.bringToFront(this.Document); } } @undoBatch @@ -1574,8 +1569,8 @@ export class DocumentView extends React.Component { this.docView && (this.docView._animateScalingTo = 0.1); // shrink doc setTimeout( action(() => { - if (useExistingLayout && custom && this.rootDoc['layout_' + view]) { - this.rootDoc.layout_fieldKey = 'layout_' + view; + if (useExistingLayout && custom && this.Document['layout_' + view]) { + this.Document.layout_fieldKey = 'layout_' + view; } else { this.setCustomView(custom, view); } @@ -1592,6 +1587,7 @@ export class DocumentView extends React.Component { ); }; + layout_fitWidthFunc = (doc: Doc) => BoolCast(this.layout_fitWidth); scaleToScreenSpace = () => (1 / (this.props.NativeDimScaling?.() || 1)) * this.screenToLocalTransform().Scale; docViewPathFunc = () => this.docViewPath; isSelected = () => this.SELECTED; @@ -1600,7 +1596,7 @@ export class DocumentView extends React.Component { else { SelectionManager.SelectView(this, extendSelection); if (focusSelection) { - DocumentManager.Instance.showDocument(this.rootDoc, { + DocumentManager.Instance.showDocument(this.Document, { willZoomCentered: true, zoomScale: 0.9, zoomTime: 500, @@ -1608,6 +1604,7 @@ export class DocumentView extends React.Component { } } }; + ShouldNotScale = () => this.shouldNotScale; NativeWidth = () => this.effectiveNativeWidth; NativeHeight = () => this.effectiveNativeHeight; PanelWidth = () => this.panelWidth; @@ -1622,8 +1619,8 @@ export class DocumentView extends React.Component { @action componentDidMount() { - this.rootDoc[DocViews].add(this); - this._disposers.updateContentsScript = reaction(() => ScriptCast(this.rootDoc.updateContentsScript)?.script?.run({ this: this.rootDoc, self: this.rootDoc }).result, emptyFunction); + this.Document[DocViews].add(this); + this._disposers.updateContentsScript = reaction(() => ScriptCast(this.Document.updateContentsScript)?.script?.run({ this: this.Document }).result, emptyFunction); this._disposers.height = reaction( // increase max auto height if document has been resized to be greater than current max () => NumCast(this.layoutDoc._height), @@ -1636,7 +1633,7 @@ export class DocumentView extends React.Component { } @action componentWillUnmount() { - this.rootDoc[DocViews].delete(this); + this.Document[DocViews].delete(this); Object.values(this._disposers).forEach(disposer => disposer?.()); !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); } @@ -1662,7 +1659,7 @@ export class DocumentView extends React.Component { console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this.textHtmlOverlay)} />
, { ...(this.htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Zoom } as any as Doc, - this.rootDoc + this.Document )}
@@ -1683,15 +1680,14 @@ export class DocumentView extends React.Component { style={{ transition: 'inherit', // this.props.dataTransition, transform: `translate(${this.centeringX}px, ${this.centeringY}px)`, - width: xshift ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`, - height: this.props.forceAutoHeight - ? undefined - : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`), + width: xshift ?? `${this.props.PanelWidth() - this.Xshift * 2}px`, + height: this.props.forceAutoHeight ? undefined : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this.props.PanelWidth()}px`), }}> { NativeDimScaling={this.NativeDimScaling} isSelected={this.isSelected} select={this.select} + layout_fitWidth={this.layout_fitWidthFunc} ScreenToLocalTransform={this.screenToLocalTransform} focus={this.props.focus || emptyFunction} ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} @@ -1719,7 +1716,7 @@ ScriptingGlobals.add(function deiconifyView(documentView: DocumentView) { }); ScriptingGlobals.add(function deiconifyViewToLightbox(documentView: DocumentView) { - LightboxView.Instance.AddDocTab(documentView.rootDoc, OpenWhere.lightbox, 'layout'); //, 0); + LightboxView.Instance.AddDocTab(documentView.Document, OpenWhere.lightbox, 'layout'); //, 0); }); ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string) { diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index de5ad1631..ba5370360 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -26,7 +26,6 @@ export enum ButtonType { TextButton = 'textBtn', MenuButton = 'menuBtn', DropdownList = 'dropdownList', - DropdownButton = 'dropdownBtn', ClickButton = 'clickBtn', ToggleButton = 'toggleBtn', ColorButton = 'colorBtn', @@ -78,7 +77,7 @@ export class FontIconBox extends DocComponent() { // Determining UI Specs @computed get label() { - return StrCast(this.rootDoc.icon_label, StrCast(this.rootDoc.title)); + return StrCast(this.dataDoc.icon_label, StrCast(this.Document.title)); } Icon = (color: string, iconFalse?: boolean) => { let icon; @@ -91,13 +90,13 @@ export class FontIconBox extends DocComponent() { return !icon ? null : icon === 'pres-trail' ? TrailsIcon(color) : ; }; @computed get dropdown() { - return BoolCast(this.rootDoc.dropDownOpen); + return BoolCast(this.Document.dropDownOpen); } @computed get buttonList() { - return StrListCast(this.rootDoc.btnList); + return StrListCast(this.Document.btnList); } @computed get type() { - return StrCast(this.rootDoc.btnType); + return StrCast(this.Document.btnType); } /** @@ -131,8 +130,8 @@ export class FontIconBox extends DocComponent() { type = 'slider'; break; } - const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ this: this.layoutDoc, self: this.rootDoc, value, _readOnly_: value === undefined }); - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); + const numScript = (value?: number) => ScriptCast(this.Document.script).script.run({ this: this.Document, value, _readOnly_: value === undefined }); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); // Script for checking the outcome of the toggle const checkResult = Number(Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3))); @@ -144,52 +143,21 @@ export class FontIconBox extends DocComponent() { showPlusMinus={false} tooltip={this.label} type={Type.PRIM} - min={NumCast(this.rootDoc.numBtnMin, 0)} - max={NumCast(this.rootDoc.numBtnMax, 100)} + min={NumCast(this.dataDoc.numBtnMin, 0)} + max={NumCast(this.dataDoc.numBtnMax, 100)} number={checkResult} - setNumber={undoable(value => numScript(value), `${this.rootDoc.title} button set from list`)} + setNumber={undoable(value => numScript(value), `${this.Document.title} button set from list`)} fillWidth /> ); } - /** - * Dropdown button - */ - @computed get dropdownButton() { - const active: string = StrCast(this.rootDoc.dropDownOpen); - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); - return ( -
{ - this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen; - this.noTooltip = this.rootDoc.dropDownOpen; - Doc.UnBrushAllDocs(); - })}> - {this.Icon(color)} - {!this.label || !FontIconBox.ShowIconLabels ? null : ( -
- {' '} - {this.label}{' '} -
- )} -
- -
- {this.rootDoc.dropDownOpen ?
{/* DROPDOWN BOX CONTENTS */}
: null} -
- ); - } - dropdownItemDown = (e: React.PointerEvent, value: string | number) => { setupMoveUpEvents( this, e, (e: PointerEvent) => { - return ScriptCast(this.rootDoc.onDragScript)?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: { doc: value, e } }).result; + return ScriptCast(this.Document.onDragScript)?.script.run({ this: this.Document, value: { doc: value, e } }).result; }, emptyFunction, emptyFunction @@ -201,7 +169,7 @@ export class FontIconBox extends DocComponent() { * Dropdown list */ @computed get dropdownListButton() { - const script = ScriptCast(this.rootDoc.script); + const script = ScriptCast(this.Document.script); let noviceList: string[] = []; let text: string | undefined; @@ -237,7 +205,7 @@ export class FontIconBox extends DocComponent() { } noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Carousel3D, CollectionViewType.Stacking, CollectionViewType.NoteTaking]; } else { - text = script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result; + text = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result; // text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily); getStyle = (val: string) => ({ fontFamily: val }); } @@ -255,7 +223,7 @@ export class FontIconBox extends DocComponent() { return ( script.script.run({ this: this.layoutDoc, self: this.rootDoc, value }), `dropdown select ${this.label}`)} + setSelectedVal={undoable(value => script.script.run({ this: this.Document, value }), `dropdown select ${this.label}`)} color={SettingsManager.userColor} background={SettingsManager.userVariantColor} type={Type.TERT} @@ -270,7 +238,7 @@ export class FontIconBox extends DocComponent() { } @computed get colorScript() { - return ScriptCast(this.rootDoc.script); + return ScriptCast(this.Document.script); } colorBatch: UndoManager.Batch | undefined; @@ -278,18 +246,18 @@ export class FontIconBox extends DocComponent() { * Color button */ @computed get colorButton() { - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const curColor = this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result ?? 'transparent'; - const tooltip: string = StrCast(this.rootDoc.toolTip); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const curColor = this.colorScript?.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result ?? 'transparent'; + const tooltip: string = StrCast(this.Document.toolTip); return ( { if (!this.colorBatch) this.colorBatch = UndoManager.StartBatch(`Set ${tooltip} color`); - this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: value, _readOnly_: false }); + this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false }); }} setFinalColor={value => { - this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: value, _readOnly_: false }); + this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false }); this.colorBatch?.end(); this.colorBatch = undefined; }} @@ -306,13 +274,13 @@ export class FontIconBox extends DocComponent() { } @computed get multiToggleButton() { // Determine the type of toggle button - const tooltip: string = StrCast(this.rootDoc.toolTip); + const tooltip: string = StrCast(this.Document.toolTip); - const script = ScriptCast(this.rootDoc.onClick); - const toggleStatus = script ? script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result : false; + const script = ScriptCast(this.Document.onClick); + const toggleStatus = script ? script.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result : false; // Colors - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const items = DocListCast(this.rootDoc.data); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const items = DocListCast(this.dataDoc.data); return ( () { color={color} background={SettingsManager.userBackgroundColor} label={this.label} - items={DocListCast(this.rootDoc.data).map(item => ({ + items={DocListCast(this.dataDoc.data).map(item => ({ icon: , tooltip: StrCast(item.toolTip), val: StrCast(item.toolType), @@ -336,14 +304,14 @@ export class FontIconBox extends DocComponent() { @computed get toggleButton() { // Determine the type of toggle button - const buttonText: string = StrCast(this.rootDoc.buttonText); - const tooltip: string = StrCast(this.rootDoc.toolTip); + const buttonText = StrCast(this.dataDoc.buttonText); + const tooltip = StrCast(this.Document.toolTip); - const script = ScriptCast(this.rootDoc.onClick); - const toggleStatus = script ? script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result : false; + const script = ScriptCast(this.Document.onClick); + const toggleStatus = script ? script.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result : false; // Colors - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const backgroundColor = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor); return ( () { //background={SettingsManager.userBackgroundColor} icon={this.Icon(color)!} label={this.label} - onPointerDown={() => script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: !toggleStatus, _readOnly_: false })} + onPointerDown={() => script.script.run({ this: this.Document, value: !toggleStatus, _readOnly_: false })} /> ); } @@ -365,20 +333,20 @@ export class FontIconBox extends DocComponent() { * Default */ @computed get defaultButton() { - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); - const tooltip: string = StrCast(this.rootDoc.toolTip); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const backgroundColor = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor); + const tooltip: string = StrCast(this.Document.toolTip); return ; } @computed get editableText() { // Script for running the toggle - const script = ScriptCast(this.rootDoc.script); + const script = ScriptCast(this.Document.script); // Function to run the script - const checkResult = script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result; + const checkResult = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result; - const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value, _readOnly_: false }).result; + const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ this: this.Document, value, _readOnly_: false }).result; return {}} />; @@ -386,16 +354,16 @@ export class FontIconBox extends DocComponent() {
- script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} /> + script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} />
); } render() { - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const tooltip = StrCast(this.rootDoc.toolTip); - const scriptFunc = () => ScriptCast(this.rootDoc.onClick)?.script.run({ this: this.layoutDoc, self: this.rootDoc, _readOnly_: false }); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const tooltip = StrCast(this.Document.toolTip); + const scriptFunc = () => ScriptCast(this.Document.onClick)?.script.run({ this: this.Document, self: this.Document, _readOnly_: false }); const btnProps = { tooltip, icon: this.Icon(color)!, label: this.label }; // prettier-ignore switch (this.type) { @@ -405,15 +373,14 @@ export class FontIconBox extends DocComponent() { case ButtonType.EditableText: return this.editableText; case ButtonType.DropdownList: return this.dropdownListButton; case ButtonType.ColorButton: return this.colorButton; - case ButtonType.DropdownButton: return this.dropdownButton; case ButtonType.MultiToggleButton: return this.multiToggleButton; case ButtonType.ToggleButton: return this.toggleButton; case ButtonType.ClickButton: case ButtonType.ToolButton: return ; case ButtonType.TextButton: return - runInAction(() => this._value = e.target.value)} - placeholder="VALUE" /> + runInAction(() => (this._value = e.target.value))} placeholder="VALUE" /> ); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index a7705ea7e..72882ac17 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -93,7 +93,7 @@ export class TreeView extends ObservableReactComponent { static _openLevelScript: Opt; private _header: React.RefObject = React.createRef(); private _tref = React.createRef(); - @observable _docRef: Opt; + @observable _docRef: Opt = undefined; private _disposers: { [name: string]: IReactionDisposer } = {}; private _editTitleScript: (() => ScriptField) | undefined; private _openScript: (() => ScriptField) | undefined; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx index 99ee5ef4e..08dfb32ad 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx @@ -1,8 +1,8 @@ import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast } from '../../../../fields/Types'; import './CollectionFreeFormView.scss'; -import * as React from 'react'; export interface CollectionFreeFormViewBackgroundGridProps { panX: () => number; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx index 2606304d0..58f6b1593 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx @@ -1,5 +1,5 @@ import { IconButton, Size, Type } from 'browndash-components'; -import { action, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { SettingsManager } from '../../../util/SettingsManager'; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx index 15e4d8360..8628ca3c3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx @@ -1,16 +1,16 @@ -import { IReactionDisposer, makeObservable, observable, runInAction } from 'mobx'; +import { makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, Field, FieldResult } from '../../../../fields/Doc'; import { InkTool } from '../../../../fields/InkField'; +import { StrCast } from '../../../../fields/Types'; import { DocumentManager } from '../../../util/DocumentManager'; import { LinkManager } from '../../../util/LinkManager'; -import { DocButtonState, DocumentLinksButton } from '../../nodes/DocumentLinksButton'; import { ObservableReactComponent } from '../../ObservableReactComponent'; -import { CollectionFreeFormInfoState, InfoState, infoState, StateEntryFunc } from './CollectionFreeFormInfoState'; +import { DocButtonState, DocumentLinksButton } from '../../nodes/DocumentLinksButton'; +import { CollectionFreeFormInfoState, InfoState, StateEntryFunc, infoState } from './CollectionFreeFormInfoState'; import { CollectionFreeFormView } from './CollectionFreeFormView'; import './CollectionFreeFormView.scss'; -import { StrCast } from '../../../../fields/Types'; export interface CollectionFreeFormInfoUIProps { Document: Doc; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 779a0bf96..95d521f65 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -1,11 +1,11 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Id } from '../../../../fields/FieldSymbols'; import { DocumentManager } from '../../../util/DocumentManager'; import { LightboxView } from '../../LightboxView'; -import './CollectionFreeFormLinksView.scss'; import { CollectionFreeFormLinkView } from './CollectionFreeFormLinkView'; -import * as React from 'react'; +import './CollectionFreeFormLinksView.scss'; @observer export class CollectionFreeFormLinksView extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx index f54726a00..ec8416303 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx @@ -1,12 +1,11 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { ScriptField } from '../../../../fields/ScriptField'; import { PresBox } from '../../nodes/trails/PresBox'; -import './CollectionFreeFormView.scss'; -import * as React from 'react'; import { CollectionFreeFormView } from './CollectionFreeFormView'; - +import './CollectionFreeFormView.scss'; export interface CollectionFreeFormPannableContentsProps { Document: Doc; viewDefDivClick?: ScriptField; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 45e24bbb2..fa8218bdd 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,6 +1,8 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; import * as mobxUtils from 'mobx-utils'; +import * as React from 'react'; +import * as uuid from 'uuid'; import CursorField from '../../../../fields/CursorField'; import { Doc, FieldResult } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; @@ -9,8 +11,6 @@ import { listSpec } from '../../../../fields/Schema'; import { Cast } from '../../../../fields/Types'; import { CollectionViewProps } from '../CollectionView'; import './CollectionFreeFormView.scss'; -import * as React from 'react'; -import * as uuid from 'uuid'; @observer export class CollectionFreeFormRemoteCursors extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 645e9cff7..cc0833698 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -37,6 +37,7 @@ import { CtrlKey } from '../../GlobalKeyHandler'; import { ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke'; import { LightboxView } from '../../LightboxView'; import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewWrapper } from '../../nodes/CollectionFreeFormDocumentView'; +import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; @@ -52,7 +53,6 @@ import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannable import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors'; import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; -import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; export type collectionFreeformViewProps = { NativeWidth?: () => number; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b22fdfa19..39d828302 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -16,19 +16,18 @@ import { DocumentType } from '../../../documents/DocumentTypes'; import { DocUtils, Docs, DocumentOptions } from '../../../documents/Documents'; import { SelectionManager } from '../../../util/SelectionManager'; import { freeformScrollMode } from '../../../util/SettingsManager'; +import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { UndoManager, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { PreviewCursor } from '../../PreviewCursor'; -import { DocumentView, OpenWhere } from '../../nodes/DocumentView'; +import { OpenWhere } from '../../nodes/DocumentView'; import { pasteImageBitmap } from '../../nodes/WebBoxRenderer'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { SubCollectionViewProps } from '../CollectionSubView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; -import { SnappingManager } from '../../../util/SnappingManager'; - interface MarqueeViewProps { getContainerTransform: () => Transform; getTransform: () => Transform; diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 1e19964d7..3e75257e5 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -7,7 +7,6 @@ import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; -import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; @@ -17,13 +16,12 @@ import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionGridView.scss'; import Grid, { Layout } from './Grid'; - @observer export class CollectionGridView extends CollectionSubView() { private _containerRef: React.RefObject = React.createRef(); private _changeListenerDisposer: Opt; // listens for changes in this.childLayoutPairs private _resetListenerDisposer: Opt; // listens for when the reset button is clicked - @observable private _rowHeight: Opt; // temporary store of row height to make change undoable + @observable private _rowHeight: Opt = undefined; // temporary store of row height to make change undoable @observable private _scroll: number = 0; // required to make sure the decorations box container updates on scroll private dropLocation: object = {}; // sets the drop location for external drops diff --git a/src/client/views/collections/collectionGrid/Grid.tsx b/src/client/views/collections/collectionGrid/Grid.tsx index 3d1d87aa0..9145d7ef1 100644 --- a/src/client/views/collections/collectionGrid/Grid.tsx +++ b/src/client/views/collections/collectionGrid/Grid.tsx @@ -1,5 +1,5 @@ -import * as React from 'react'; import { observer } from 'mobx-react'; +import * as React from 'react'; import '../../../../../node_modules/react-grid-layout/css/styles.css'; import '../../../../../node_modules/react-resizable/css/styles.css'; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index e12bcd8b0..5bea59e7b 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -4,13 +4,13 @@ import { Button } from 'browndash-components'; import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { returnFalse } from '../../../../Utils'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { returnFalse } from '../../../../Utils'; import { DragManager, dropActionType } from '../../../util/DragManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { Transform } from '../../../util/Transform'; -import { undoable, undoBatch } from '../../../util/UndoManager'; +import { undoBatch, undoable } from '../../../util/UndoManager'; import { DocumentView } from '../../nodes/DocumentView'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionMulticolumnView.scss'; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 7dbc18e60..3043eb0f8 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -1,9 +1,9 @@ import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { returnFalse } from '../../../../Utils'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { returnFalse } from '../../../../Utils'; import { DragManager, dropActionType } from '../../../util/DragManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; @@ -12,7 +12,6 @@ import { CollectionSubView } from '../CollectionSubView'; import './CollectionMultirowView.scss'; import HeightLabel from './MultirowHeightLabel'; import ResizeBar from './MultirowResizer'; - interface HeightSpecifier { magnitude: number; unit: string; diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx index 868b1140d..ea99bff2e 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -1,12 +1,12 @@ -import * as React from 'react'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { observable, action } from 'mobx'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { DimUnit } from './CollectionMulticolumnView'; import { UndoManager } from '../../../util/UndoManager'; -import { StyleProviderFunc } from '../../nodes/DocumentView'; import { StyleProp } from '../../StyleProvider'; +import { StyleProviderFunc } from '../../nodes/DocumentView'; +import { DimUnit } from './CollectionMulticolumnView'; interface ResizerProps { width: number; diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx index 9985a9fba..a9579d931 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx @@ -1,27 +1,25 @@ -import * as React from "react"; -import { observer } from "mobx-react"; -import { computed } from "mobx"; -import { Doc } from "../../../../fields/Doc"; -import { NumCast, StrCast, BoolCast } from "../../../../fields/Types"; -import { EditableView } from "../../EditableView"; -import { DimUnit } from "./CollectionMulticolumnView"; +import { computed } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc } from '../../../../fields/Doc'; +import { BoolCast, NumCast, StrCast } from '../../../../fields/Types'; +import { EditableView } from '../../EditableView'; +import { DimUnit } from './CollectionMulticolumnView'; interface WidthLabelProps { layout: Doc; collectionDoc: Doc; - decimals?: number; } @observer export default class WidthLabel extends React.Component { - @computed private get contents() { - const { layout, decimals } = this.props; + const { layout } = this.props; const getUnit = () => StrCast(layout.dimUnit); - const getMagnitude = () => String(+NumCast(layout.dimMagnitude).toFixed(decimals ?? 3)); + const getMagnitude = () => String(+NumCast(layout.dimMagnitude).toFixed(3)); return ( -
+
{ @@ -50,7 +48,6 @@ export default class WidthLabel extends React.Component { } render() { - return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null); + return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : null; } - -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx b/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx index aa5439fa4..878c7ff3c 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx @@ -1,10 +1,10 @@ -import * as React from "react"; -import { observer } from "mobx-react"; -import { computed } from "mobx"; -import { Doc } from "../../../../fields/Doc"; -import { NumCast, StrCast, BoolCast } from "../../../../fields/Types"; -import { EditableView } from "../../EditableView"; -import { DimUnit } from "./CollectionMultirowView"; +import { computed } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc } from '../../../../fields/Doc'; +import { BoolCast, NumCast, StrCast } from '../../../../fields/Types'; +import { EditableView } from '../../EditableView'; +import { DimUnit } from './CollectionMultirowView'; interface HeightLabelProps { layout: Doc; @@ -14,14 +14,13 @@ interface HeightLabelProps { @observer export default class HeightLabel extends React.Component { - @computed private get contents() { const { layout, decimals } = this.props; const getUnit = () => StrCast(layout.dimUnit); const getMagnitude = () => String(+NumCast(layout.dimMagnitude).toFixed(decimals ?? 3)); return ( -
+
{ @@ -50,7 +49,6 @@ export default class HeightLabel extends React.Component { } render() { - return BoolCast(this.props.collectionDoc.showHeightLabels) ? this.contents : (null); + return BoolCast(this.props.collectionDoc.showHeightLabels) ? this.contents : null; } - -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx index 5a9d6a82c..7dee65e58 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx @@ -1,12 +1,12 @@ -import * as React from 'react'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { observable, action } from 'mobx'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { DimUnit } from './CollectionMultirowView'; import { UndoManager } from '../../../util/UndoManager'; import { StyleProp } from '../../StyleProvider'; import { StyleProviderFunc } from '../../nodes/DocumentView'; +import { DimUnit } from './CollectionMultirowView'; interface ResizerProps { height: number; diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index 04443b4a7..5f8b412be 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -1,7 +1,7 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable } from 'mobx'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { Colors } from '../../global/globalEnums'; import './CollectionSchemaView.scss'; diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 06073b52c..85e97f95f 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -1,3 +1,4 @@ +import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, makeObservable, observable } from 'mobx'; @@ -7,18 +8,17 @@ import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { Cast, DocCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; +import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; +import { undoBatch } from '../../util/UndoManager'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView'; import { LinkInfo } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; -import { undoBatch } from '../../util/UndoManager'; -import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { DocumentType } from '../../documents/DocumentTypes'; interface LinkMenuItemProps { groupType: string; diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index 5460a6daf..7e344dd7a 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -1,16 +1,16 @@ import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import { EditorView } from 'prosemirror-view'; -import { Doc } from '../../../fields/Doc'; +import * as React from 'react'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils'; +import { Doc } from '../../../fields/Doc'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; +import { DefaultStyleProvider } from '../StyleProvider'; import { OpenWhere } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { SearchBox } from '../search/SearchBox'; -import { DefaultStyleProvider } from '../StyleProvider'; import './LinkPopup.scss'; -import * as React from 'react'; interface LinkPopupProps { linkFrom?: () => Doc | undefined; @@ -29,7 +29,7 @@ interface LinkPopupProps { @observer export class LinkPopup extends React.Component { @observable private linkURL: string = ''; - @observable public view?: EditorView; + @observable public view?: EditorView = undefined; // TODO: should check for valid URL @undoBatch diff --git a/src/client/views/linking/LinkRelationshipSearch.tsx b/src/client/views/linking/LinkRelationshipSearch.tsx index 3e7f5be74..0902d53b2 100644 --- a/src/client/views/linking/LinkRelationshipSearch.tsx +++ b/src/client/views/linking/LinkRelationshipSearch.tsx @@ -1,6 +1,6 @@ import { observer } from 'mobx-react'; -import './LinkEditor.scss'; import * as React from 'react'; +import './LinkEditor.scss'; interface link_relationshipSearchProps { results: string[] | undefined; diff --git a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx index 72b63cf8f..bce2b296f 100644 --- a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx +++ b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx @@ -3,12 +3,12 @@ import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { InkTool } from '../../../../fields/InkField'; import { SelectionManager } from '../../../util/SelectionManager'; +import { SnappingManager } from '../../../util/SnappingManager'; import { CollectionDockingView } from '../../collections/CollectionDockingView'; -import { DocumentView, OpenWhereMod } from '../../nodes/DocumentView'; +import { OpenWhereMod } from '../../nodes/DocumentView'; import { NewLightboxView } from '../NewLightboxView'; import './ButtonMenu.scss'; import { IButtonMenu } from './utils'; -import { SnappingManager } from '../../../util/SnappingManager'; export const ButtonMenu = (props: IButtonMenu) => { return ( diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx index 6980e31c1..3d159c3e3 100644 --- a/src/client/views/newlightbox/NewLightboxView.tsx +++ b/src/client/views/newlightbox/NewLightboxView.tsx @@ -2,28 +2,28 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../../Utils'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { LinkManager } from '../../util/LinkManager'; import { SelectionManager } from '../../util/SelectionManager'; +import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; -import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline'; -import { TabDocView } from '../collections/TabDocView'; import { GestureOverlay } from '../GestureOverlay'; import { LightboxView } from '../LightboxView'; -import { DocumentView, OpenWhere } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; -import { IRecommendation } from './components'; +import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline'; +import { TabDocView } from '../collections/TabDocView'; +import { DocumentView, OpenWhere } from '../nodes/DocumentView'; import { ExploreView } from './ExploreView'; -import { emptyBounds, IBounds } from './ExploreView/utils'; +import { IBounds, emptyBounds } from './ExploreView/utils'; import { NewLightboxHeader } from './Header'; import './NewLightboxView.scss'; import { RecommendationList } from './RecommendationList'; -import { SnappingManager } from '../../util/SnappingManager'; +import { IRecommendation } from './components'; enum LightboxStatus { RECOMMENDATIONS = 'recommendations', @@ -50,15 +50,15 @@ export class NewLightboxView extends React.Component { return this._doc; } private static LightboxDocTemplate = () => NewLightboxView._layoutTemplate; - @observable private static _layoutTemplate: Opt; - @observable private static _layoutTemplateString: Opt; - @observable private static _doc: Opt; - @observable private static _docTarget: Opt; + @observable private static _layoutTemplate: Opt = undefined; + @observable private static _layoutTemplateString: Opt = undefined; + @observable private static _doc: Opt = undefined; + @observable private static _docTarget: Opt = undefined; @observable private static _docFilters: string[] = []; // filters - private static _savedState: Opt; + private static _savedState: Opt = undefined; private static _history: Opt<{ doc: Doc; target?: Doc }[]> = []; @observable private static _future: Opt = []; - @observable private static _docView: Opt; + @observable private static _docView: Opt = undefined; // keywords @observable private static _keywords: string[] = []; diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 4c36d2fcb..12e8e1a69 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -44,8 +44,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { private _annotationLayer: React.RefObject = React.createRef(); anchorMenuClick?: () => undefined | ((anchor: Doc) => void); crop: ((region: Doc | undefined, addCrop?: boolean) => Doc | undefined) | undefined; - @observable schemaDataVizChildren: any; - @observable _marqueeing: number[] | undefined; + @observable schemaDataVizChildren: any = undefined; + @observable _marqueeing: number[] | undefined = undefined; @observable _savedAnnotations = new ObservableMap(); @computed get annotationLayer() { TraceMobx(); diff --git a/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx b/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx index 3cb5125da..24023077f 100644 --- a/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx +++ b/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx @@ -1,15 +1,14 @@ -import * as React from 'react'; -import './SchemaCSVPopUp.scss'; +import { IconButton } from 'browndash-components'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { CgClose } from 'react-icons/cg'; +import { Utils, emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; -import { Button, IconButton, Type } from 'browndash-components'; import { StrCast } from '../../../../fields/Types'; -import { MarqueeView } from '../../collections/collectionFreeForm/MarqueeView'; -import { Utils, emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { DragManager } from '../../../util/DragManager'; import { DocumentView } from '../DocumentView'; -import { CgClose } from 'react-icons/cg'; +import './SchemaCSVPopUp.scss'; interface SchemaCSVPopUpProps {} @@ -56,13 +55,11 @@ export class SchemaCSVPopUp extends React.Component {
{this.heading('Schema Table as Data Visualization Doc')}
-
-
this.drag(e)}> - -
+
+
this.drag(e)}> +
+
); @@ -88,9 +85,10 @@ export class SchemaCSVPopUp extends React.Component { return embedding; }; if (this.view && sourceAnchorCreator && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { - DragManager.StartAnchorAnnoDrag(e.target instanceof HTMLElement ? [e.target] : [], - new DragManager.AnchorAnnoDragData(this.view, sourceAnchorCreator, targetCreator), downX, downY, { - dragComplete: e => {this.setVisible(false);}, + DragManager.StartAnchorAnnoDrag(e.target instanceof HTMLElement ? [e.target] : [], new DragManager.AnchorAnnoDragData(this.view, sourceAnchorCreator, targetCreator), downX, downY, { + dragComplete: e => { + this.setVisible(false); + }, }); return true; } @@ -108,4 +106,4 @@ export class SchemaCSVPopUp extends React.Component {
); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 227c993c7..9e9a43b34 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -1,7 +1,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ColorPicker, EditableText, IconButton, Size, Type } from 'browndash-components'; import * as d3 from 'd3'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { FaFillDrip } from 'react-icons/fa'; @@ -11,10 +11,10 @@ import { listSpec } from '../../../../../fields/Schema'; import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; import { Docs } from '../../../../documents/Documents'; import { undoable } from '../../../../util/UndoManager'; +import { ObservableReactComponent } from '../../../ObservableReactComponent'; import { PinProps, PresBox } from '../../trails'; import { scaleCreatorNumerical, yAxisCreator } from '../utils/D3Utils'; import './Chart.scss'; -import { ObservableReactComponent } from '../../../ObservableReactComponent'; export interface HistogramProps { Document: Doc; @@ -461,7 +461,7 @@ export class Histogram extends ObservableReactComponent { if (this._histogramData.length > 0 || !this.parentViz) { return this._props.axes.length >= 1 ? ( -
+
{ private _lineChartSvg: d3.Selection | undefined; @observable _currSelected: SelectedDataPoint | undefined = undefined; // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates - constructor(props:any) { + constructor(props: any) { super(props); makeObservable(this); } - @computed get _tableDataIds() { return !this.parentViz ? this._props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows); } @@ -359,7 +358,7 @@ export class LineChart extends ObservableReactComponent { const selectedPt = this._currSelected ? `{ ${this._props.axes[0]}: ${this._currSelected.x} ${this._props.axes[1]}: ${this._currSelected.y} }` : 'none'; if (this._lineChartData.length > 0 || !this.parentViz || this.parentViz.length == 0) { return this._props.axes.length >= 2 && /\d/.test(this._props.records[0][this._props.axes[0]]) && /\d/.test(this._props.records[0][this._props.axes[1]]) ? ( -
+
{ />
- {selectedPt != 'none' ? -
+ {selectedPt != 'none' ? ( +
{`Selected: ${selectedPt}`} - -
- : null} + +
+ ) : null}
) : ( {'first use table view to select two numerical axes to plot'} diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index e644870da..e67556cd0 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -1,7 +1,7 @@ import { Checkbox } from '@mui/material'; import { ColorPicker, EditableText, Size, Type } from 'browndash-components'; import * as d3 from 'd3'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { FaFillDrip } from 'react-icons/fa'; @@ -11,9 +11,9 @@ import { listSpec } from '../../../../../fields/Schema'; import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; import { Docs } from '../../../../documents/Documents'; import { undoable } from '../../../../util/UndoManager'; +import { ObservableReactComponent } from '../../../ObservableReactComponent'; import { PinProps, PresBox } from '../../trails'; import './Chart.scss'; -import { ObservableReactComponent } from '../../../ObservableReactComponent'; export interface PieChartProps { Document: Doc; @@ -356,7 +356,7 @@ export class PieChart extends ObservableReactComponent { if (this._pieChartData.length > 0 || !this.parentViz) { return this._props.axes.length >= 1 ? ( -
+
{ return (this.viewScale * this._tableHeight) / this._tableDataIds.length; } @computed get startID() { - return this.rowHeight ? Math.max(Math.floor(this._scrollTop / this.rowHeight)-1, 0) : 0; + return this.rowHeight ? Math.max(Math.floor(this._scrollTop / this.rowHeight) - 1, 0) : 0; } @computed get endID() { console.log('start = ' + this.startID + ' container = ' + this._tableContainerHeight + ' scale = ' + this.viewScale + ' row = ' + this.rowHeight); @@ -169,7 +169,7 @@ export class TableBox extends ObservableReactComponent { return (
{ if (this._props.layoutDoc && e.key === 'a' && (e.ctrlKey || e.metaKey)) { @@ -226,7 +226,7 @@ export class TableBox extends ObservableReactComponent { {this._tableDataIds - .filter((rowId, i) => this.startID-2 <= i && i <= this.endID+2) + .filter((rowId, i) => this.startID - 2 <= i && i <= this.endID + 2) ?.map(rowId => ( ; export interface JsxBindings { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cc7fca8d2..f8f4b94a2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,10 +1,11 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { Dropdown, DropdownType, Type } from 'browndash-components'; +import { Howl } from 'howler'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; -import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal'; import * as React from 'react'; +import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal'; import { Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; import { AclPrivate, Animation, AudioPlay, DocViews } from '../../../fields/DocSymbols'; @@ -53,7 +54,6 @@ import { LinkAnchorBox } from './LinkAnchorBox'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { PresEffect, PresEffectDirection } from './trails'; import { PinProps, PresBox } from './trails/PresBox'; -import { Howl } from 'howler'; interface Window { MediaRecorder: MediaRecorder; @@ -138,7 +138,6 @@ export interface DocComponentView { dragStarting?: (snapToDraggedDoc: boolean, showGroupDragTarget: boolean, visited: Set) => void; incrementalRendering?: () => void; infoUI?: () => JSX.Element | null; - getCenter?: (xf: Transform) => { X: number; Y: number }; screenBounds?: () => Opt<{ left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } }>; ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; @@ -1516,7 +1515,7 @@ export class DocumentView extends ObservableReactComponent { const docuBox = this.docView.ContentDiv.getElementsByClassName('linkAnchorBox-cont'); if (docuBox.length) return { ...docuBox[0].getBoundingClientRect(), center: undefined }; } - return { left, top, right, bottom, center: this.ComponentView?.getCenter?.(xf) }; + return { left, top, right, bottom }; }; public iconify(finished?: () => void, animateTime?: number) { diff --git a/src/client/views/nodes/FaceRectangle.tsx b/src/client/views/nodes/FaceRectangle.tsx index 8d03bf57a..46bc6eb03 100644 --- a/src/client/views/nodes/FaceRectangle.tsx +++ b/src/client/views/nodes/FaceRectangle.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; -import { observer } from 'mobx-react'; import { observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; import { RectangleTemplate } from './FaceRectangles'; @observer diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx index 26e720c0d..ade4225d9 100644 --- a/src/client/views/nodes/FaceRectangles.tsx +++ b/src/client/views/nodes/FaceRectangles.tsx @@ -1,8 +1,8 @@ +import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; -import { Cast, NumCast } from '../../../fields/Types'; -import { observer } from 'mobx-react'; import { Id } from '../../../fields/FieldSymbols'; +import { Cast, NumCast } from '../../../fields/Types'; import FaceRectangle from './FaceRectangle'; interface FaceRectanglesProps { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index f4c5167a5..008f10f26 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { DateField } from '../../../fields/DateField'; import { Doc, Field, FieldResult, Opt } from '../../../fields/Doc'; import { List } from '../../../fields/List'; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index fd8d8ef56..7bc9d3f85 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,7 +1,6 @@ import { Tooltip } from '@mui/material'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { ObservableGroupMap } from 'mobx-utils'; import * as React from 'react'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../Utils'; import { Doc, Field } from '../../../fields/Doc'; @@ -11,13 +10,13 @@ import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { EditableView } from '../EditableView'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider } from '../StyleProvider'; import { OpenWhere } from './DocumentView'; import { FieldViewProps } from './FieldView'; import { KeyValueBox } from './KeyValueBox'; import './KeyValueBox.scss'; import './KeyValuePair.scss'; -import { ObservableReactComponent } from '../ObservableReactComponent'; // Represents one row in a key value plane @@ -35,12 +34,11 @@ export class KeyValuePair extends ObservableReactComponent { @observable private isPointerOver = false; @observable public isChecked = false; private checkbox = React.createRef(); - constructor(props:any) { + constructor(props: any) { super(props); makeObservable(this); } - @action handleCheck = (e: React.ChangeEvent) => { this.isChecked = e.currentTarget.checked; diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index 32300d60a..8ad0b7dde 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../fields/Doc'; import { LinkManager } from '../../util/LinkManager'; import './LinkDescriptionPopup.scss'; diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index d0a9f10b4..ea23ecbea 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -2,13 +2,14 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import wiki from 'wikijs'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils'; import { DocServer } from '../../DocServer'; -import { Docs } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; +import { Docs } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; @@ -16,10 +17,9 @@ import { LinkManager } from '../../util/LinkManager'; import { SearchUtil } from '../../util/SearchUtil'; import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; -import * as React from 'react'; -import { ObservableReactComponent } from '../ObservableReactComponent'; export class LinkInfo { private static _instance: Opt; diff --git a/src/client/views/nodes/LoadingBox.tsx b/src/client/views/nodes/LoadingBox.tsx index 27d73a585..adccc9db6 100644 --- a/src/client/views/nodes/LoadingBox.tsx +++ b/src/client/views/nodes/LoadingBox.tsx @@ -1,4 +1,4 @@ -import { action, observable, runInAction } from 'mobx'; +import { observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import ReactLoading from 'react-loading'; diff --git a/src/client/views/nodes/MapBox/AnimationUtility.ts b/src/client/views/nodes/MapBox/AnimationUtility.ts index 42dfa59b7..35153f439 100644 --- a/src/client/views/nodes/MapBox/AnimationUtility.ts +++ b/src/client/views/nodes/MapBox/AnimationUtility.ts @@ -1,13 +1,10 @@ -import mapboxgl from 'mapbox-gl'; -import { MercatorCoordinate } from 'mapbox-gl'; -import { MapRef } from 'react-map-gl'; -import * as React from 'react'; -import * as d3 from 'd3'; import * as turf from '@turf/turf'; import { Position } from '@turf/turf'; -import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from 'geojson'; -import { observer } from 'mobx-react'; -import { action, computed, observable, runInAction, makeObservable } from 'mobx'; +import * as d3 from 'd3'; +import { Feature, GeoJsonProperties, Geometry } from 'geojson'; +import mapboxgl, { MercatorCoordinate } from 'mapbox-gl'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; +import { MapRef } from 'react-map-gl'; export enum AnimationStatus { START = 'start', diff --git a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx index f9607becf..7e99795b5 100644 --- a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx @@ -1,15 +1,15 @@ -import * as React from 'react'; -import { observer } from 'mobx-react'; -import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; +import { IconLookup, faAdd, faCalendarDays, faRoute } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { IconButton } from 'browndash-components'; import { IReactionDisposer, ObservableMap, reaction } from 'mobx'; -import { Doc, Opt } from '../../../../fields/Doc'; +import { observer } from 'mobx-react'; +import * as React from 'react'; import { returnFalse, unimplementedFunction } from '../../../../Utils'; +import { Doc, Opt } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; import { SelectionManager } from '../../../util/SelectionManager'; -import { IconButton } from 'browndash-components'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { SettingsManager } from '../../../util/SettingsManager'; -import { IconLookup, faAdd, faCalendarDays, faRoute } from '@fortawesome/free-solid-svg-icons'; +import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; @observer export class DirectionsAnchorMenu extends AntimodeMenu { diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx index 1b1b74e7c..08bea5d9d 100644 --- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx @@ -1,26 +1,23 @@ +import { IconLookup, faAdd, faArrowDown, faArrowLeft, faArrowsRotate, faBicycle, faCalendarDays, faCar, faDiamondTurnRight, faEdit, faPersonWalking, faRoute } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import * as React from 'react'; +import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/material'; +import { IconButton } from 'browndash-components'; +import { Position } from 'geojson'; import { IReactionDisposer, ObservableMap, action, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { Doc, NumListCast, Opt } from '../../../../fields/Doc'; +import * as React from 'react'; +import { CirclePicker, ColorResult } from 'react-color'; import { returnFalse, setupMoveUpEvents, unimplementedFunction } from '../../../../Utils'; +import { Doc, Opt } from '../../../../fields/Doc'; +import { NumCast, StrCast } from '../../../../fields/Types'; +import { CalendarManager } from '../../../util/CalendarManager'; import { SelectionManager } from '../../../util/SelectionManager'; -import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; -// import { GPTPopup, GPTPopupMode } from './../../GPTPopup/GPTPopup'; -import { Button, IconButton } from 'browndash-components'; import { SettingsManager } from '../../../util/SettingsManager'; +import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; import './MapAnchorMenu.scss'; -import { NumCast, StrCast } from '../../../../fields/Types'; -import { IconLookup, faDiamondTurnRight, faCalendarDays, faEdit, faAdd, faRoute, faArrowLeft, faLocationDot, faArrowDown, faCar, faBicycle, faPersonWalking, faUpload, faArrowsRotate } from '@fortawesome/free-solid-svg-icons'; -import { DirectionsAnchorMenu } from './DirectionsAnchorMenu'; -import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/material'; import { MapboxApiUtility, TransportationType } from './MapboxApiUtility'; -import { MapBox } from './MapBox'; -import { List } from '../../../../fields/List'; import { MarkerIcons } from './MarkerIcons'; -import { CirclePicker, ColorResult } from 'react-color'; -import { Position } from 'geojson'; -import { CalendarManager } from '../../../util/CalendarManager'; +// import { GPTPopup, GPTPopupMode } from './../../GPTPopup/GPTPopup'; type MapAnchorMenuType = 'standard' | 'routeCreation' | 'calendar' | 'customize' | 'route'; @@ -52,7 +49,6 @@ export class MapAnchorMenu extends AntimodeMenu { public UpdateMarkerColor: (color: string) => void = unimplementedFunction; public UpdateMarkerIcon: (iconKey: string) => void = unimplementedFunction; - public Hide: () => void = unimplementedFunction; public OpenAnimationPanel: (routeDoc: Doc | undefined) => void = unimplementedFunction; @@ -74,22 +70,21 @@ export class MapAnchorMenu extends AntimodeMenu { private title: string | undefined = undefined; public setPinDoc(pinDoc: Doc | undefined) { - if (pinDoc){ + if (pinDoc) { this.pinDoc = pinDoc; this.title = StrCast(pinDoc.title ? pinDoc.title : `${NumCast(pinDoc.longitude)}, ${NumCast(pinDoc.latitude)}`); } - } public setRouteDoc(routeDoc: Doc | undefined) { - if (routeDoc){ + if (routeDoc) { this.routeDoc = routeDoc; this.title = StrCast(routeDoc.title ?? 'Map route'); } } @action - public Reset(){ + public Reset() { this.destinationSelected = false; this.currentRouteInfoMap = undefined; this.destinationFeatures = []; @@ -296,34 +291,23 @@ export class MapAnchorMenu extends AntimodeMenu { return undefined; }; - getDirectionsButton: JSX.Element = ( - } - color={SettingsManager.userColor} /> - ) + getDirectionsButton: JSX.Element = (} color={SettingsManager.userColor} />); getAddToCalendarButton = (docType: string): JSX.Element => { return ( - { - CalendarManager.Instance.open(undefined, docType === 'pin' ? this.pinDoc : this.routeDoc) - }} - icon={} - color={SettingsManager.userColor} + { + CalendarManager.Instance.open(undefined, docType === 'pin' ? this.pinDoc : this.routeDoc); + }} + icon={} + color={SettingsManager.userColor} /> - ) - - } + ); + }; addToCalendarButton: JSX.Element = ( - CalendarManager.Instance.open(undefined, this.pinDoc)} - icon={} - color={SettingsManager.userColor} /> - ) + CalendarManager.Instance.open(undefined, this.pinDoc)} icon={} color={SettingsManager.userColor} /> + ); getLinkNoteToDocButton = (docType: string): JSX.Element => { return ( @@ -335,8 +319,8 @@ export class MapAnchorMenu extends AntimodeMenu { color={SettingsManager.userColor} />
- ) - } + ); + }; linkNoteToPinOrRoutenButton: JSX.Element = (
@@ -347,16 +331,9 @@ export class MapAnchorMenu extends AntimodeMenu { color={SettingsManager.userColor} />
- ) - - customizePinButton: JSX.Element = ( - } - color={SettingsManager.userColor} - /> - ) + ); + + customizePinButton: JSX.Element = (} color={SettingsManager.userColor} />); centerOnPinButton: JSX.Element = ( { icon={} color={SettingsManager.userColor} /> - ) + ); backButton: JSX.Element = ( { icon={} color={SettingsManager.userColor} /> - ) + ); addRouteButton: JSX.Element = ( { icon={} color={SettingsManager.userColor} /> - ) + ); getDeleteButton = (type: string) => { return ( @@ -393,17 +370,10 @@ export class MapAnchorMenu extends AntimodeMenu { icon={} color={SettingsManager.userColor} /> - ) - } + ); + }; - animateRouteButton: JSX.Element = ( - this.OpenAnimationPanel(this.routeDoc)} - icon={} - color={SettingsManager.userColor} - /> - ) + animateRouteButton: JSX.Element = ( this.OpenAnimationPanel(this.routeDoc)} icon={} color={SettingsManager.userColor} />); revertToOriginalMarkerButton = ( { icon={} color={SettingsManager.userColor} /> - ) + ); render() { const buttons = ( diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 7db139d74..ffd52fb0e 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -1,8 +1,17 @@ +import { IconLookup, faCircleXmark, faGear, faPause, faPlay, faRotate } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Checkbox, FormControlLabel, TextField } from '@mui/material'; +import * as turf from '@turf/turf'; import { IconButton, Size, Type } from 'browndash-components'; +import * as d3 from 'd3'; +import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, Position } from 'geojson'; +import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl'; import { IReactionDisposer, ObservableMap, action, autorun, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { CirclePicker, ColorResult } from 'react-color'; +import { Layer, MapProvider, MapRef, Map as MapboxMap, Marker, Source, ViewState, ViewStateChangeEvent } from 'react-map-gl'; +import { MarkerEvent } from 'react-map-gl/dist/esm/types'; import { Utils, emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; import { DocCss, Highlight } from '../../../../fields/DocSymbols'; @@ -22,22 +31,13 @@ import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; -import { MapAnchorMenu } from './MapAnchorMenu'; -import { ControlPosition, Layer, MapProvider, MapRef, Map as MapboxMap, Marker, MarkerProps, Source, ViewState, ViewStateChangeEvent } from 'react-map-gl'; -import './MapBox.scss'; -// import { GeocoderControl } from './GeocoderControl'; -import { IconLookup, faCircleXmark, faGear, faPause, faPlay, faRotate } from '@fortawesome/free-solid-svg-icons'; -import { Checkbox, FormControlLabel, TextField } from '@mui/material'; -import * as turf from '@turf/turf'; -import * as d3 from 'd3'; -import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, Position } from 'geojson'; -import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl'; -import { CirclePicker, ColorResult } from 'react-color'; -import { MarkerEvent } from 'react-map-gl/dist/esm/types'; import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons'; import { AnimationSpeed, AnimationStatus, AnimationUtility } from './AnimationUtility'; +import { MapAnchorMenu } from './MapAnchorMenu'; +import './MapBox.scss'; import { MapboxApiUtility, TransportationType } from './MapboxApiUtility'; import { MarkerIcons } from './MarkerIcons'; +// import { GeocoderControl } from './GeocoderControl'; // amongus /** @@ -480,7 +480,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { @@ -650,7 +650,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { - console.log('deleting') + console.log('deleting'); if (this.selectedPinOrRoute) { // Removes filter Doc.setDocFilter(this.Document, 'latitude', this.selectedPinOrRoute.latitude, 'remove'); @@ -677,15 +677,12 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (this.selectedPinOrRoute) { @@ -882,8 +879,8 @@ export class MapBox extends ViewBoxAnnotatableComponent { return ( <> @@ -1423,20 +1417,14 @@ export class MapBox extends ViewBoxAnnotatableComponent
|
- } - /> + } />
|
|
-
+
Select Line Color:
- this.setAnimationLineColor(color)} /> + this.setAnimationLineColor(color)} />
-
@@ -1478,7 +1466,7 @@ export class MapBox extends ViewBoxAnnotatableComponent) => { const bearing = parseInt(e.target.value); if (!isNaN(bearing) && this._mapRef.current) { - console.log('bearing change') + console.log('bearing change'); const fixedBearing = Math.max(0, Math.min(360, bearing)); this._mapRef.current.setBearing(fixedBearing); this.dataDoc.map_bearing = fixedBearing; @@ -1489,7 +1477,7 @@ export class MapBox extends ViewBoxAnnotatableComponent) => { const pitch = parseInt(e.target.value); if (!isNaN(pitch) && this._mapRef.current) { - console.log('pitch change') + console.log('pitch change'); const fixedPitch = Math.max(0, Math.min(85, pitch)); this._mapRef.current.setPitch(fixedPitch); this.dataDoc.map_pitch = fixedPitch; @@ -1648,7 +1636,7 @@ export class MapBox extends ViewBoxAnnotatableComponent = React.createRef(); -// @observable private _overlayAnnoInfo: Opt; +// @observable private _overlayAnnoInfo: Opt = undefined; // showInfo = action((anno: Opt) => (this._overlayAnnoInfo = anno)); // public static LayoutString(fieldKey: string) { // return FieldView.LayoutString(MapBox2, fieldKey); diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index 6a14427c0..70037f29c 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -1,33 +1,31 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import BingMapsReact from 'bingmaps-react'; import { Button, EditableText, IconButton, Type } from 'browndash-components'; -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx'; +import { IReactionDisposer, ObservableMap, action, computed, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { MapProvider, Map as MapboxMap } from 'react-map-gl'; +import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents } from '../../../../Utils'; import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; import { DocCss, Highlight } from '../../../../fields/DocSymbols'; -import { Id } from '../../../../fields/FieldSymbols'; import { DocCast, NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; -import { Docs, DocUtils } from '../../../documents/Documents'; import { DocumentType } from '../../../documents/DocumentTypes'; +import { DocUtils, Docs } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { LinkManager } from '../../../util/LinkManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; -import { undoable, UndoManager } from '../../../util/UndoManager'; -import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; +import { UndoManager, undoable } from '../../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; -import { Colors } from '../../global/globalEnums'; import { SidebarAnnos } from '../../SidebarAnnos'; +import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; +import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; +import { MapAnchorMenu } from '../MapBox/MapAnchorMenu'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; import './MapBox.scss'; -import { MapAnchorMenu } from '../MapBox/MapAnchorMenu'; -import { MapProvider, Map as MapboxMap } from 'react-map-gl'; // amongus /** @@ -351,7 +349,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 733febd2d..7f1d6b049 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -48,7 +48,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent(); @observable private _searching: boolean = false; - @observable private _pdf: Opt; + @observable private _pdf: Opt = undefined; @observable private _pageControls = false; @computed get pdfUrl() { diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx index e75b1ab6f..135db64e0 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -6,8 +6,9 @@ import QuestionMarkIcon from '@mui/icons-material/QuestionMark'; import ReplayIcon from '@mui/icons-material/Replay'; import { Box, Button, Checkbox, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, FormControl, FormControlLabel, FormGroup, IconButton, LinearProgress, Stack } from '@mui/material'; import Typography from '@mui/material/Typography'; -import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { NumListCast } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { BoolCast, NumCast, StrCast } from '../../../../fields/Types'; @@ -19,7 +20,6 @@ import questions from './PhysicsSimulationQuestions.json'; import tutorials from './PhysicsSimulationTutorial.json'; import Wall from './PhysicsSimulationWall'; import Weight from './PhysicsSimulationWeight'; -import * as React from 'react'; interface IWallProps { length: number; diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx index f5077a07e..3b232ddd0 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx @@ -1,7 +1,7 @@ import { computed, IReactionDisposer, makeObservable, reaction } from 'mobx'; import { observer } from 'mobx-react'; -import './PhysicsSimulationBox.scss'; import * as React from 'react'; +import './PhysicsSimulationBox.scss'; interface IWallProps { length: number; diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx index 061a46f03..3b2fc033d 100644 --- a/src/client/views/nodes/RadialMenu.tsx +++ b/src/client/views/nodes/RadialMenu.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import './RadialMenu.scss'; import { RadialMenuItem, RadialMenuProps } from './RadialMenuItem'; diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx index c931202f1..10a90befd 100644 --- a/src/client/views/nodes/RadialMenuItem.tsx +++ b/src/client/views/nodes/RadialMenuItem.tsx @@ -1,7 +1,7 @@ -import * as React from 'react'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { UndoManager } from '../../util/UndoManager'; export interface RadialMenuProps { diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx index f01642236..658cfb1ca 100644 --- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx +++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx @@ -8,15 +8,15 @@ import { List } from '../../../../fields/List'; import { BoolCast, DocCast } from '../../../../fields/Types'; import { VideoField } from '../../../../fields/URLField'; import { Upload } from '../../../../server/SharedMediaTypes'; -import { Docs } from '../../../documents/Documents'; import { DocumentType } from '../../../documents/DocumentTypes'; +import { Docs } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; import { Presentation } from '../../../util/TrackMovements'; import { undoBatch } from '../../../util/UndoManager'; -import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView'; import { ViewBoxBaseComponent } from '../../DocComponent'; +import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView'; import { media_state } from '../AudioBox'; import { FieldView, FieldViewProps } from '../FieldView'; import { VideoBox } from '../VideoBox'; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index d5d31b407..79ed69cdd 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -1,5 +1,5 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import * as React from 'react'; // import { Canvas } from '@react-three/fiber'; import { computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 7e7eaee45..8e506ec64 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -2,25 +2,23 @@ let ReactTextareaAutocomplete = require('@webscopeio/react-textarea-autocomplete import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { returnAlways, returnEmptyString } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { returnAlways, returnEmptyString, returnTrue } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; -import { InteractionUtils } from '../../util/InteractionUtils'; +import { ScriptManager } from '../../util/ScriptManager'; import { CompileScript, ScriptParam } from '../../util/Scripting'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; -import { ScriptManager } from '../../util/ScriptManager'; import { ContextMenu } from '../ContextMenu'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { EditableView } from '../EditableView'; -import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { OverlayView } from '../OverlayView'; +import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { DocumentIconContainer } from './DocumentIcon'; -import { DocFocusOptions, DocumentView } from './DocumentView'; import './ScriptingBox.scss'; const _global = (window /* browser */ || global) /* node */ as any; diff --git a/src/client/views/nodes/TaskCompletedBox.tsx b/src/client/views/nodes/TaskCompletedBox.tsx index 9aab8c5a9..c9e15d314 100644 --- a/src/client/views/nodes/TaskCompletedBox.tsx +++ b/src/client/views/nodes/TaskCompletedBox.tsx @@ -1,15 +1,15 @@ -import * as React from 'react'; +import { Fade } from '@mui/material'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import './TaskCompletedBox.scss'; -import { observable, action } from 'mobx'; -import { Fade } from '@mui/material'; @observer export class TaskCompletionBox extends React.Component<{}> { @observable public static taskCompleted: boolean = false; @observable public static popupX: number = 500; @observable public static popupY: number = 150; - @observable public static textDisplayed: string; + @observable public static textDisplayed: string = ''; @action public static toggleTaskCompleted = () => { diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index f205dbd56..8e9cfe3d7 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -74,8 +74,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent(); @observable _screenCapture = false; @observable _clicking = false; // used for transition between showing/hiding timeline @@ -86,7 +86,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent(){ +export class CalendarBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string = 'calendar') { return FieldView.LayoutString(CalendarBox, fieldKey); } - componentDidMount(): void { - - } + componentDidMount(): void {} - componentWillUnmount(): void { - - } + componentWillUnmount(): void {} - _calendarRef = React.createRef() + _calendarRef = React.createRef(); - get dateRangeStr (){ + get dateRangeStr() { return StrCast(this.Document.date_range); } - // Choose a calendar view based on the date range - get calendarViewType (): CalendarView { + // Choose a calendar view based on the date range + get calendarViewType(): CalendarView { const [fromDate, toDate] = dateRangeStrToDates(this.dateRangeStr); if (fromDate.getFullYear() !== toDate.getFullYear() || fromDate.getMonth() !== toDate.getMonth()) return 'multi-month'; @@ -43,92 +38,83 @@ export class CalendarBox extends ViewBoxBaseComponent(){ return 'week'; } - get calendarStartDate () { - return this.dateRangeStr.split("|")[0]; + get calendarStartDate() { + return this.dateRangeStr.split('|')[0]; } - get calendarToDate () { - return this.dateRangeStr.split("|")[1]; + get calendarToDate() { + return this.dateRangeStr.split('|')[1]; } - get childDocs (): Doc[] { + get childDocs(): Doc[] { return this.childDocs; // get all sub docs for a calendar } - docBackgroundColor (type: string): string { + docBackgroundColor(type: string): string { // TODO: Return a different color based on the event type return 'blue'; } - get calendarEvents (): EventSourceInput | undefined { + get calendarEvents(): EventSourceInput | undefined { if (this.childDocs.length === 0) return undefined; return this.childDocs.map((doc, idx) => { const docTitle = StrCast(doc.title); const docDateRange = StrCast(doc.date_range); const [startDate, endDate] = dateRangeStrToDates(docDateRange); const docType = doc.type; - const docDescription = doc.description ? StrCast(doc.description): ""; + const docDescription = doc.description ? StrCast(doc.description) : ''; return { title: docTitle, start: startDate, end: endDate, allDay: false, - classNames:[StrCast(docType)], // will determine the style + classNames: [StrCast(docType)], // will determine the style editable: false, // subject to change in the future backgroundColor: this.docBackgroundColor(StrCast(doc.type)), color: 'white', extendedProps: { - description: docDescription + description: docDescription, }, - - } - - }) + }; + }); } handleEventClick = (arg: EventClickArg) => { // TODO: open popover with event description, option to open CalendarManager and change event date, delete event, etc. - } + }; calendarEl: HTMLElement = document.getElementById('calendar-box-v1')!; // https://fullcalendar.io get calendar() { - return new Calendar(this.calendarEl, - { - plugins: [this.calendarViewType === 'multi-month' ? multiMonthPlugin : dayGridPlugin], - headerToolbar: { - left: 'prev,next today', - center: 'title', - right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' - }, - initialDate: this.calendarStartDate, - navLinks: true, - editable: false, - displayEventTime: false, - displayEventEnd: false, - events: this.calendarEvents, - eventClick: this.handleEventClick - } - ) - + return new Calendar(this.calendarEl, { + plugins: [this.calendarViewType === 'multi-month' ? multiMonthPlugin : dayGridPlugin], + headerToolbar: { + left: 'prev,next today', + center: 'title', + right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek', + }, + initialDate: this.calendarStartDate, + navLinks: true, + editable: false, + displayEventTime: false, + displayEventEnd: false, + events: this.calendarEvents, + eventClick: this.handleEventClick, + }); } - - constructor(props: any){ + constructor(props: any) { super(props); makeObservable(this); } - render(){ + render() { return ( -
-
- -
-
+
+
+
); - } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 6332b200d..1002ee403 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -1,17 +1,17 @@ import { action, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { NodeSelection } from 'prosemirror-state'; +import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; import { Height, Width } from '../../../../fields/DocSymbols'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnFalse, returnTrue, Utils } from '../../../../Utils'; +import { emptyFunction, returnFalse, Utils } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { Docs, DocUtils } from '../../../documents/Documents'; import { Transform } from '../../../util/Transform'; import { DocFocusOptions, DocumentView } from '../DocumentView'; import { FormattedTextBox } from './FormattedTextBox'; -import * as React from 'react'; export class DashDocView { dom: HTMLSpanElement; // container for label and value @@ -83,7 +83,7 @@ export class DashDocViewInternal extends React.Component { _disposers: { [name: string]: IReactionDisposer } = {}; _textBox: FormattedTextBox; @observable _dashDoc: Doc | undefined = undefined; - @observable _finalLayout: any; + @observable _finalLayout: any = undefined; @observable _width: number = 0; @observable _height: number = 0; diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx index 331ed1980..7e655531e 100644 --- a/src/client/views/nodes/formattedText/EquationView.tsx +++ b/src/client/views/nodes/formattedText/EquationView.tsx @@ -1,14 +1,13 @@ -import EquationEditor from './EquationEditor'; -import { IReactionDisposer, trace } from 'mobx'; +import { IReactionDisposer } from 'mobx'; import { observer } from 'mobx-react'; import { TextSelection } from 'prosemirror-state'; +import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; import { StrCast } from '../../../../fields/Types'; import './DashFieldView.scss'; +import EquationEditor from './EquationEditor'; import { FormattedTextBox } from './FormattedTextBox'; -import * as React from 'react'; -import { AnyArray } from 'mongoose'; export class EquationView { dom: HTMLDivElement; // container for label and value diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index ad2fab8b0..8bf8abafa 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -11,6 +11,7 @@ import { keymap } from 'prosemirror-keymap'; import { Fragment, Mark, Node, Slice } from 'prosemirror-model'; import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from 'prosemirror-state'; import { EditorView } from 'prosemirror-view'; +import * as React from 'react'; import { BsMarkdownFill } from 'react-icons/bs'; import { DateField } from '../../../../fields/DateField'; import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc'; @@ -70,9 +71,8 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu'; import { RichTextRules } from './RichTextRules'; import { schema } from './schema_rts'; import { SummaryView } from './SummaryView'; -// import * as applyDevTools from 'prosemirror-dev-tools'; -import * as React from 'react'; export const GoogleRef = 'googleDocId'; +// import * as applyDevTools from 'prosemirror-dev-tools'; type PullHandler = (exportState: Opt, dataDoc: Doc) => void; export interface FormattedTextBoxProps {} diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 4881070fd..3b31f2d17 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -32,7 +32,7 @@ export class RichTextMenu extends AntimodeMenu { private _linkToRef = React.createRef(); layoutDoc: Doc | undefined; - @observable public view?: EditorView; + @observable public view?: EditorView = undefined; public editorProps: FieldViewProps | undefined; public _brushMap: Map> = new Map(); diff --git a/src/client/views/nodes/importBox/ImportElementBox.tsx b/src/client/views/nodes/importBox/ImportElementBox.tsx index 9dc0c5180..b573f7c48 100644 --- a/src/client/views/nodes/importBox/ImportElementBox.tsx +++ b/src/client/views/nodes/importBox/ImportElementBox.tsx @@ -1,13 +1,11 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { returnFalse } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue } from '../../../../Utils'; -import { Transform } from '../../../util/Transform'; import { ViewBoxBaseComponent } from '../../DocComponent'; -import { DefaultStyleProvider } from '../../StyleProvider'; -import { DocumentView, DocumentViewInternal } from '../DocumentView'; +import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; -import * as React from 'react'; @observer export class ImportElementBox extends ViewBoxBaseComponent() { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index e213b2fc5..0305689e7 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1,8 +1,8 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast, FieldResult, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; import { Animation } from '../../../../fields/DocSymbols'; import { Copy, Id } from '../../../../fields/FieldSymbols'; @@ -24,7 +24,7 @@ import { SerializationHelper } from '../../../util/SerializationHelper'; import { SettingsManager } from '../../../util/SettingsManager'; import { undoBatch, UndoManager } from '../../../util/UndoManager'; import { CollectionDockingView } from '../../collections/CollectionDockingView'; -import { CollectionFreeFormView, computeTimelineLayout, MarqueeViewBounds } from '../../collections/collectionFreeForm'; +import { CollectionFreeFormView, MarqueeViewBounds } from '../../collections/collectionFreeForm'; import { CollectionStackedTimeline } from '../../collections/CollectionStackedTimeline'; import { CollectionView } from '../../collections/CollectionView'; import { TreeView } from '../../collections/TreeView'; @@ -83,12 +83,12 @@ export class PresBox extends ViewBoxBaseComponent() { _batch: UndoManager.Batch | undefined = undefined; // undo batch for dragging sliders which generate multiple scene edit events as the cursor moves _keyTimer: NodeJS.Timeout | undefined; // timer for turning off transition flag when key frame change has completed. Need to clear this if you do a second navigation before first finishes, or else first timer can go off during second naviation. _unmounting = false; // flag that view is unmounting used to block RemFromMap from deleting things + _presTimer: NodeJS.Timeout | undefined; @observable public static Instance: PresBox; @observable _isChildActive = false; @observable _moveOnFromAudio: boolean = true; - @observable _presTimer!: NodeJS.Timeout; @observable _eleArray: HTMLElement[] = []; @observable _dragArray: HTMLElement[] = []; diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index cf19ff6bc..5ea9e9979 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -1,18 +1,17 @@ -import * as React from 'react'; import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types'; import { LinkFollower } from '../../util/LinkFollower'; +import { LinkManager } from '../../util/LinkManager'; import { undoBatch } from '../../util/UndoManager'; import { OpenWhere } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { AnchorMenu } from './AnchorMenu'; import './Annotation.scss'; -import { LinkManager } from '../../util/LinkManager'; -import { Rect } from 'react-measure'; interface IAnnotationProps extends FieldViewProps { anno: Doc; diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index db21d9a3d..da8a88803 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -1,20 +1,20 @@ -import * as React from 'react'; -import './GPTPopup.scss'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Button, IconButton, Type } from 'browndash-components'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { CgClose } from 'react-icons/cg'; import ReactLoading from 'react-loading'; import { TypeAnimation } from 'react-type-animation'; +import { Utils } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; -import { DocUtils, Docs } from '../../../documents/Documents'; -import { Button, IconButton, Type } from 'browndash-components'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { CgClose } from 'react-icons/cg'; -import { AnchorMenu } from '../AnchorMenu'; -import { gptImageCall } from '../../../apis/gpt/GPT'; import { Networking } from '../../../Network'; -import { Utils } from '../../../../Utils'; +import { gptImageCall } from '../../../apis/gpt/GPT'; +import { DocUtils, Docs } from '../../../documents/Documents'; import { ObservableReactComponent } from '../../ObservableReactComponent'; +import { AnchorMenu } from '../AnchorMenu'; +import './GPTPopup.scss'; export enum GPTPopupMode { SUMMARY, diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index e342c25b3..b6d027d30 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -302,7 +302,7 @@ export class PDFViewer extends ObservableReactComponent { } }; - @observable private _scrollTimer: any; + @observable private _scrollTimer: any = undefined; onScroll = (e: React.UIEvent) => { if (this._mainCont.current && !this._forcedScroll) { diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index ccfccb771..14187833f 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -2,24 +2,23 @@ import { Tooltip } from '@mui/material'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../../fields/Doc'; +import { Doc, DocListCastAsync, Field } from '../../../fields/Doc'; import { DirectLinks } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { DocCast, StrCast } from '../../../fields/Types'; -import { DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; +import { DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { LinkManager } from '../../util/LinkManager'; +import { SearchUtil } from '../../util/SearchUtil'; +import { SettingsManager } from '../../util/SettingsManager'; import { undoBatch } from '../../util/UndoManager'; -import { CollectionDockingView } from '../collections/CollectionDockingView'; import { ViewBoxBaseComponent } from '../DocComponent'; +import { CollectionDockingView } from '../collections/CollectionDockingView'; +import { IRecommendation, Recommendation } from '../newlightbox/components'; +import { fetchRecommendations } from '../newlightbox/utils'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './SearchBox.scss'; -import { fetchRecommendations } from '../newlightbox/utils'; -import { IRecommendation, Recommendation } from '../newlightbox/components'; -import { Colors } from '../global/globalEnums'; -import { SettingsManager } from '../../util/SettingsManager'; -import { SearchUtil } from '../../util/SearchUtil'; const DAMPENING_FACTOR = 0.9; const MAX_ITERATIONS = 25; diff --git a/src/client/views/selectedDoc/SelectedDocView.tsx b/src/client/views/selectedDoc/SelectedDocView.tsx index 39e778b76..daacb368b 100644 --- a/src/client/views/selectedDoc/SelectedDocView.tsx +++ b/src/client/views/selectedDoc/SelectedDocView.tsx @@ -1,14 +1,14 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ListBox } from 'browndash-components'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { emptyFunction } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; import { DocumentManager } from '../../util/DocumentManager'; -import { DocFocusOptions } from '../nodes/DocumentView'; -import { emptyFunction } from '../../../Utils'; import { SettingsManager } from '../../util/SettingsManager'; +import { DocFocusOptions } from '../nodes/DocumentView'; export interface SelectedDocViewProps { selectedDocs: Doc[]; diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 0f3487cd1..575d5849e 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -16,15 +16,15 @@ import { ReportManager } from '../../util/reportManager/ReportManager'; import { ServerStats } from '../../util/ServerStats'; import { SettingsManager } from '../../util/SettingsManager'; import { SharingManager } from '../../util/SharingManager'; +import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { CollectionDockingView } from '../collections/CollectionDockingView'; import { CollectionLinearView } from '../collections/collectionLinear'; import { DashboardView } from '../DashboardView'; import { Colors } from '../global/globalEnums'; -import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; +import { DocumentViewInternal } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; import './TopBar.scss'; -import { SnappingManager } from '../../util/SnappingManager'; /** * ABOUT: This is the topbar in Dash, which included the current Dashboard as well as access to information on the user diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index f1739a41a..94458563e 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -3,16 +3,15 @@ import { faPhoneSlash, faSync } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; +import { SnappingManager } from '../../util/SnappingManager'; import '../../views/nodes/WebBox.scss'; import { CollectionFreeFormDocumentViewProps } from '../nodes/CollectionFreeFormDocumentView'; -import { DocumentView } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './DashWebRTCVideo.scss'; import { hangup, initialize, refreshVideos } from './WebCamLogic'; -import * as React from 'react'; -import { SnappingManager } from '../../util/SnappingManager'; /** * This models the component that will be rendered, that can be used as a doc that will reflect the video cams. diff --git a/src/debug/Repl.tsx b/src/debug/Repl.tsx index b8081648f..a9f7c085f 100644 --- a/src/debug/Repl.tsx +++ b/src/debug/Repl.tsx @@ -1,13 +1,13 @@ +import { computed, observable } from 'mobx'; +import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; -import { observer } from 'mobx-react'; -import { observable, computed } from 'mobx'; +import { DocServer } from '../client/DocServer'; +import { resolvedPorts } from '../client/util/CurrentUserUtils'; import { CompileScript } from '../client/util/Scripting'; -import { makeInterface } from '../fields/Schema'; import { ObjectField } from '../fields/ObjectField'; import { RefField } from '../fields/RefField'; -import { DocServer } from '../client/DocServer'; -import { resolvedPorts } from '../client/util/CurrentUserUtils'; +import { makeInterface } from '../fields/Schema'; @observer class Repl extends React.Component { diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index 02038c426..f46adef77 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -1,19 +1,19 @@ -import { action, configure, observable, ObservableMap, Lambda } from 'mobx'; +import { action, configure, observable } from 'mobx'; +import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { observer } from 'mobx-react'; -import { Doc, Field, FieldResult, Opt } from '../fields/Doc'; import { DocServer } from '../client/DocServer'; +import { resolvedPorts } from '../client/util/CurrentUserUtils'; +import { CompileScript } from '../client/util/Scripting'; +import { EditableView } from '../client/views/EditableView'; +import CursorField from '../fields/CursorField'; +import { DateField } from '../fields/DateField'; +import { Doc, Field, FieldResult } from '../fields/Doc'; import { Id } from '../fields/FieldSymbols'; import { List } from '../fields/List'; -import { URLField } from '../fields/URLField'; -import { EditableView } from '../client/views/EditableView'; -import { CompileScript } from '../client/util/Scripting'; import { RichTextField } from '../fields/RichTextField'; -import { DateField } from '../fields/DateField'; import { ScriptField } from '../fields/ScriptField'; -import CursorField from '../fields/CursorField'; -import { resolvedPorts } from '../client/util/CurrentUserUtils'; +import { URLField } from '../fields/URLField'; DateField; URLField; diff --git a/src/fields/CursorField.ts b/src/fields/CursorField.ts index 46f5a8e1c..84917ae53 100644 --- a/src/fields/CursorField.ts +++ b/src/fields/CursorField.ts @@ -1,8 +1,7 @@ -import { ObjectField } from './ObjectField'; -import { observable } from 'mobx'; +import { createSimpleSchema, object, serializable } from 'serializr'; import { Deserializable } from '../client/util/SerializationHelper'; -import { serializable, createSimpleSchema, object, date } from 'serializr'; -import { FieldChanged, ToScriptString, ToString, Copy } from './FieldSymbols'; +import { Copy, FieldChanged, ToScriptString, ToString } from './FieldSymbols'; +import { ObjectField } from './ObjectField'; export type CursorPosition = { x: number; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 8903a9f97..9dc3c173d 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -265,8 +265,8 @@ export class Doc extends RefField { @observable public [DocAcl]: { [key: string]: symbol } = {}; @observable public [DocCss]: number = 0; // incrementer denoting a change to CSS layout @observable public [DirectLinks] = new ObservableSet(); - @observable public [AudioPlay]: any; // meant to store sound object from Howl - @observable public [Animation]: Opt; + @observable public [AudioPlay]: any = undefined; // meant to store sound object from Howl + @observable public [Animation]: Opt = undefined; @observable public [Highlight]: boolean = false; @observable public [Brushed]: boolean = false; @observable public [DocViews] = new ObservableSet(); diff --git a/src/fields/List.ts b/src/fields/List.ts index 8c8ff1ea3..b8ad552d2 100644 --- a/src/fields/List.ts +++ b/src/fields/List.ts @@ -2,7 +2,7 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { alias, list, serializable } from 'serializr'; import { DocServer } from '../client/DocServer'; import { ScriptingGlobals } from '../client/util/ScriptingGlobals'; -import { afterDocDeserialize, autoObject, Deserializable } from '../client/util/SerializationHelper'; +import { Deserializable, afterDocDeserialize, autoObject } from '../client/util/SerializationHelper'; import { Field } from './Doc'; import { FieldTuples, Self, SelfProxy } from './DocSymbols'; import { Copy, FieldChanged, Parent, ToScriptString, ToString } from './FieldSymbols'; @@ -11,7 +11,7 @@ import { ProxyField } from './Proxy'; import { RefField } from './RefField'; import { listSpec } from './Schema'; import { Cast } from './Types'; -import { deleteProperty, getter, setter, containedFieldChangedHandler } from './util'; +import { containedFieldChangedHandler, deleteProperty, getter, setter } from './util'; function toObjectField(field: Field) { return field instanceof RefField ? new ProxyField(field) : field; @@ -102,8 +102,8 @@ class ListImpl extends ObjectField { items.length === 0 && deleteCount ? { op: '$remFromSet', items: removed, hint: { start, deleteCount }, length: list.__fieldTuples.length } : items.length && !deleteCount && start === list.__fieldTuples.length - ? { op: '$addToSet', items, length: list.__fieldTuples.length } - : undefined + ? { op: '$addToSet', items, length: list.__fieldTuples.length } + : undefined ); return res.map(toRealField); }), diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts index c076f5fe1..3a46e3581 100644 --- a/src/fields/Proxy.ts +++ b/src/fields/Proxy.ts @@ -1,12 +1,12 @@ -import { Deserializable } from '../client/util/SerializationHelper'; -import { Field, FieldWaiting, Opt } from './Doc'; +import { action, computed, observable, runInAction } from 'mobx'; import { primitive, serializable } from 'serializr'; -import { observable, action, runInAction, computed } from 'mobx'; import { DocServer } from '../client/DocServer'; -import { RefField } from './RefField'; -import { ObjectField } from './ObjectField'; -import { Id, Copy, ToScriptString, ToString, ToValue } from './FieldSymbols'; import { scriptingGlobal } from '../client/util/ScriptingGlobals'; +import { Deserializable } from '../client/util/SerializationHelper'; +import { Field, FieldWaiting, Opt } from './Doc'; +import { Copy, Id, ToScriptString, ToString, ToValue } from './FieldSymbols'; +import { ObjectField } from './ObjectField'; +import { RefField } from './RefField'; function deserializeProxy(field: any) { if (!field.cache.field) { diff --git a/src/fields/util.ts b/src/fields/util.ts index 545fe4478..b73520999 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -1,11 +1,11 @@ import { $mobx, action, observable, runInAction, trace } from 'mobx'; import { computedFn } from 'mobx-utils'; +import { returnZero } from '../Utils'; import { DocServer } from '../client/DocServer'; import { LinkManager } from '../client/util/LinkManager'; import { SerializationHelper } from '../client/util/SerializationHelper'; import { UndoManager } from '../client/util/UndoManager'; -import { returnZero } from '../Utils'; -import { aclLevel, Doc, DocListCast, Field, FieldResult, HierarchyMapping, ReverseHierarchyMap, StrListCast, updateCachedAcls } from './Doc'; +import { Doc, DocListCast, Field, FieldResult, HierarchyMapping, ReverseHierarchyMap, StrListCast, aclLevel, updateCachedAcls } from './Doc'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, DocAcl, DocData, DocLayout, FieldKeys, ForceServerWrite, Height, Initializing, SelfProxy, UpdatingFromServer, Width } from './DocSymbols'; import { FieldChanged, Id, Parent, ToValue } from './FieldSymbols'; import { List } from './List'; diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index d2598c2db..e333e6a2e 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -1,19 +1,19 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import * as rp from 'request-promise'; +import { Utils } from '../Utils'; import { DocServer } from '../client/DocServer'; -import { Docs } from '../client/documents/Documents'; import { Networking } from '../client/Network'; +import { Docs } from '../client/documents/Documents'; import { MainViewModal } from '../client/views/MainViewModal'; import { Doc, Opt } from '../fields/Doc'; import { List } from '../fields/List'; import { listSpec } from '../fields/Schema'; import { Cast } from '../fields/Types'; -import { Utils } from '../Utils'; import './ImageUpload.scss'; import { MobileInterface } from './MobileInterface'; -import * as React from 'react'; const { default: { DFLT_IMAGE_NATIVE_DIM } } = require('../client/views/global/globalCssVariables.module.scss'); // prettier-ignore export interface ImageUploadProps { Document: Doc; // Target document for upload (upload location) diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 2e595e4bc..23e19585a 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { DocServer } from '../client/DocServer'; import { DragManager } from '../client/util/DragManager'; import { Doc } from '../fields/Doc'; diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index bdd657575..e3d8f9394 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -1,52 +1,33 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { - faTasks, - faReply, - faQuoteLeft, - faHandPointLeft, - faFolderOpen, + faAddressCard, + faAlignLeft, + faAlignRight, faAngleDoubleLeft, - faExternalLinkSquareAlt, - faMobile, - faThLarge, - faWindowClose, - faEdit, - faTrashAlt, - faPalette, faAngleRight, + faArrowDown, + faArrowLeft, + faArrowRight, + faArrowUp, + faArrowsAltH, + faAsterisk, + faBars, faBell, - faTrash, + faBolt, + faBook, + faBrain, + faBullseye, + faCalculator, faCamera, - faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, - faArrowsAltH, - faPlus, - faMinus, - faTerminal, - faToggleOn, - faFile as fileSolid, - faExternalLinkAlt, - faLocationArrow, - faSearch, - faFileDownload, - faStop, - faCalculator, - faWindowMaximize, - faAddressCard, - faQuestionCircle, - faArrowLeft, - faArrowRight, - faArrowDown, - faArrowUp, - faBolt, - faBullseye, faCaretUp, faCat, faCheck, + faChevronLeft, faChevronRight, faClipboard, faClone, @@ -54,76 +35,95 @@ import { faCommentAlt, faCompressArrowsAlt, faCut, + faEdit, faEllipsisV, faEraser, faExclamation, + faExpand, + faExternalLinkAlt, + faExternalLinkSquareAlt, + faEye, faFileAlt, faFileAudio, + faFileDownload, faFilePdf, faFilm, faFilter, + faFolderOpen, faFont, faGlobeAsia, + faHandPointLeft, faHighlighter, + faHome, + faImage, + faLocationArrow, + faLongArrowAltLeft, faLongArrowAltRight, faMicrophone, + faMinus, + faMobile, faMousePointer, faMusic, faObjectGroup, + faPaintBrush, + faPalette, faPause, faPen, faPenNib, faPhone, faPlay, + faPlus, faPortrait, + faQuestionCircle, + faQuoteLeft, faRedoAlt, + faReply, + faSearch, faStamp, faStickyNote, + faStop, + faTasks, + faTerminal, + faTh, + faThLarge, faThumbtack, + faTimes, + faToggleOn, + faTrash, + faTrashAlt, faTree, faTv, - faBook, faUndoAlt, faVideo, - faAsterisk, - faBrain, - faImage, - faPaintBrush, - faTimes, - faEye, - faHome, - faLongArrowAltLeft, - faBars, - faTh, - faChevronLeft, - faAlignRight, - faAlignLeft, + faWindowClose, + faWindowMaximize, + faFile as fileSolid, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Docs, DocumentOptions, DocUtils } from '../client/documents/Documents'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../Utils'; import { CollectionViewType, DocumentType } from '../client/documents/DocumentTypes'; +import { Docs, DocumentOptions } from '../client/documents/Documents'; import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; import { ScriptingGlobals } from '../client/util/ScriptingGlobals'; -import { SettingsManager, ColorScheme } from '../client/util/SettingsManager'; +import { SettingsManager } from '../client/util/SettingsManager'; import { Transform } from '../client/util/Transform'; import { UndoManager } from '../client/util/UndoManager'; -import { TabDocView } from '../client/views/collections/TabDocView'; import { GestureOverlay } from '../client/views/GestureOverlay'; +import { TabDocView } from '../client/views/collections/TabDocView'; import { AudioBox } from '../client/views/nodes/AudioBox'; import { DocumentView } from '../client/views/nodes/DocumentView'; -import { RichTextMenu } from '../client/views/nodes/formattedText/RichTextMenu'; import { RadialMenu } from '../client/views/nodes/RadialMenu'; +import { RichTextMenu } from '../client/views/nodes/formattedText/RichTextMenu'; import { Doc, DocListCast } from '../fields/Doc'; import { InkTool } from '../fields/InkField'; import { List } from '../fields/List'; import { ScriptField } from '../fields/ScriptField'; import { Cast, FieldValue, StrCast } from '../fields/Types'; -import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero } from '../Utils'; -import { Uploader } from './ImageUpload'; import './AudioUpload.scss'; +import { Uploader } from './ImageUpload'; import './ImageUpload.scss'; import './MobileInterface.scss'; diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts index 8f21966ae..d46977816 100644 --- a/src/typings/index.d.ts +++ b/src/typings/index.d.ts @@ -14,9 +14,7 @@ declare module 'pdfjs-dist/web/pdf_viewer'; declare module 'react-jsx-parser'; declare module 'express-flash'; -declare module 'connect-flash' { - interface flash {} -} +declare module 'connect-flash'; declare module 'connect-mongo'; declare module '@mui/material'; diff --git a/test/test.ts b/test/test.ts index 489aa3025..ee14a9340 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,37 +1,41 @@ import { expect } from 'chai'; import 'mocha'; const { JSDOM } = require('jsdom'); -const dom = new JSDOM("", { - url: `http://localhost:${resolvedPorts.server}` +const dom = new JSDOM('', { + url: `http://localhost:${resolvedPorts.server}`, }); (global as any).window = dom.window; - -import { autorun, reaction } from "mobx"; +import { reaction } from 'mobx'; +import { resolvedPorts } from '../src/client/util/CurrentUserUtils'; import { Doc } from '../src/fields/Doc'; +import { createSchema, defaultSpec, makeInterface } from '../src/fields/Schema'; import { Cast } from '../src/fields/Types'; -import { createSchema, makeInterface, defaultSpec } from '../src/fields/Schema'; import { ImageField } from '../src/fields/URLField'; -import { resolvedPorts } from '../src/client/util/CurrentUserUtils'; -describe("Document", () => { +describe('Document', () => { it('should hold fields', () => { - const key = "Test"; - const key2 = "Test2"; + const key = 'Test'; + const key2 = 'Test2'; const field = 15; const doc = new Doc(); doc[key] = field; - const getField = Cast(doc[key], "number"); - const getField2 = Cast(doc[key2], "number"); + const getField = Cast(doc[key], 'number'); + const getField2 = Cast(doc[key2], 'number'); expect(getField).to.equal(field); expect(getField2).to.equal(undefined); }); it('should update', () => { const doc = new Doc(); - const key = "Test"; - const key2 = "Test2"; + const key = 'Test'; + const key2 = 'Test2'; let ran = false; - reaction(() => doc[key], (field) => { ran = true; }); + reaction( + () => doc[key], + field => { + ran = true; + } + ); expect(ran).to.equal(false); doc[key2] = 4; @@ -44,55 +48,55 @@ describe("Document", () => { }); const testSchema1 = createSchema({ - a: "number", - b: "string", - c: "boolean", + a: 'number', + b: 'string', + c: 'boolean', d: ImageField, - e: Doc + e: Doc, }); type TestDoc = makeInterface<[typeof testSchema1]>; const TestDoc = makeInterface(testSchema1); const testSchema2 = createSchema({ - a: defaultSpec("boolean", true), - b: defaultSpec("number", 5), - c: defaultSpec("string", "hello world") + a: defaultSpec('boolean', true), + b: defaultSpec('number', 5), + c: defaultSpec('string', 'hello world'), }); type TestDoc2 = makeInterface<[typeof testSchema2]>; const TestDoc2 = makeInterface(testSchema2); const testSchema3 = createSchema({ - a: TestDoc2 + a: TestDoc2, }); type TestDoc3 = makeInterface<[typeof testSchema3]>; const TestDoc3 = makeInterface(testSchema3); -describe("Schema", () => { - it("should do the right thing 1", () => { - const test1 = new Doc; - const test2 = new Doc; - const ifield = new ImageField(new URL("http://google.com")); +describe('Schema', () => { + it('should do the right thing 1', () => { + const test1 = new Doc(); + const test2 = new Doc(); + const ifield = new ImageField(new URL('http://google.com')); test1.a = 5; - test1.b = "hello"; + test1.b = 'hello'; test1.c = true; test1.d = ifield; test1.e = test2; const doc = TestDoc(test1); expect(doc.a).to.equal(5); - expect(doc.b).to.equal("hello"); + expect(doc.b).to.equal('hello'); expect(doc.c).to.equal(true); expect(doc.d).to.equal(ifield); expect(doc.e).to.equal(test2); }); - it("should do the right thing 2", () => { - const test1 = new Doc; - const test2 = new Doc; - const ifield = new ImageField(new URL("http://google.com")); - test1.a = "hello"; + it('should do the right thing 2', () => { + const test1 = new Doc(); + const test2 = new Doc(); + const ifield = new ImageField(new URL('http://google.com')); + test1.a = 'hello'; test1.b = 5; test1.c = test2; test1.d = true; @@ -105,11 +109,11 @@ describe("Schema", () => { expect(doc.e).to.equal(undefined); }); - it("should do the right thing 3", () => { - const test1 = new Doc; - const test2 = new Doc; - const ifield = new ImageField(new URL("http://google.com")); - test1.a = "hello"; + it('should do the right thing 3', () => { + const test1 = new Doc(); + const test2 = new Doc(); + const ifield = new ImageField(new URL('http://google.com')); + test1.a = 'hello'; test1.b = 5; test1.c = test2; test1.d = true; @@ -122,40 +126,40 @@ describe("Schema", () => { expect(doc.e).to.equal(undefined); }); - it("should do the right thing 4", () => { + it('should do the right thing 4', () => { const doc = TestDoc2(); expect(doc.a).to.equal(true); expect(doc.b).to.equal(5); - expect(doc.c).to.equal("hello world"); + expect(doc.c).to.equal('hello world'); - const d2 = new Doc; + const d2 = new Doc(); d2.a = false; d2.b = 4; - d2.c = "goodbye"; + d2.c = 'goodbye'; const doc2 = TestDoc2(d2); expect(doc2.a).to.equal(false); expect(doc2.b).to.equal(4); - expect(doc2.c).to.equal("goodbye"); + expect(doc2.c).to.equal('goodbye'); - const d3 = new Doc; - d3.a = "hello"; + const d3 = new Doc(); + d3.a = 'hello'; d3.b = false; d3.c = 5; const doc3 = TestDoc2(d3); expect(doc3.a).to.equal(true); expect(doc3.b).to.equal(5); - expect(doc3.c).to.equal("hello world"); + expect(doc3.c).to.equal('hello world'); }); - it("should do the right thing 5", async () => { - const test1 = new Doc; - const test2 = new Doc; + it('should do the right thing 5', async () => { + const test1 = new Doc(); + const test2 = new Doc(); const doc = TestDoc3(test1); expect(doc.a).to.equal(undefined); test1.a = test2; const doc2 = (await doc.a)!; expect(doc2.a).to.equal(true); expect(doc2.b).to.equal(5); - expect(doc2.c).to.equal("hello world"); + expect(doc2.c).to.equal('hello world'); }); }); -- cgit v1.2.3-70-g09d2 From fdc0bf7c54af252178f587709630d36726484b91 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 2 Jan 2024 13:26:53 -0500 Subject: fixing more .props => ._props refernces. --- src/client/util/BranchingTrailManager.tsx | 2 +- src/client/util/CaptureManager.tsx | 2 +- src/client/util/DictationManager.ts | 8 +-- src/client/util/DragManager.ts | 2 +- src/client/util/GroupMemberView.tsx | 29 +++++---- src/client/util/SelectionManager.ts | 10 +-- src/client/util/SharingManager.tsx | 2 +- src/client/util/TrackMovements.ts | 4 +- src/client/views/DocComponent.tsx | 3 +- src/client/views/DocumentButtonBar.tsx | 74 +++------------------- src/client/views/DocumentDecorations.tsx | 10 +-- src/client/views/FilterPanel.tsx | 18 ++++-- src/client/views/InkStrokeProperties.ts | 2 +- src/client/views/PropertiesButtons.tsx | 6 +- src/client/views/StyleProvider.tsx | 2 +- src/client/views/TemplateMenu.tsx | 6 +- .../views/collections/CollectionCarousel3DView.tsx | 4 +- .../views/collections/CollectionCarouselView.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 2 +- src/client/views/collections/CollectionMenu.tsx | 4 +- .../views/collections/CollectionNoteTakingView.tsx | 2 +- .../views/collections/CollectionPileView.tsx | 4 +- .../collections/CollectionStackedTimeline.tsx | 2 +- src/client/views/collections/TreeView.tsx | 6 +- .../CollectionFreeFormLinkView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collectionGrid/CollectionGridView.tsx | 72 ++++++++++----------- .../collectionMulticolumn/MulticolumnResizer.tsx | 11 +--- .../collectionMulticolumn/MultirowResizer.tsx | 11 +--- .../nodes/DataVizBox/components/LineChart.tsx | 6 +- .../views/nodes/DataVizBox/components/TableBox.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 16 ++--- src/client/views/nodes/MapBox/MapBox2.tsx | 34 +++++----- src/client/views/nodes/MapBox/MapPushpinBox.tsx | 4 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 54 ++++++++-------- .../nodes/PhysicsBox/PhysicsSimulationBox.tsx | 34 +++++----- .../views/nodes/RecordingBox/RecordingBox.tsx | 6 +- src/client/views/nodes/ScreenshotBox.tsx | 50 +++++++-------- src/client/views/nodes/ScriptingBox.tsx | 14 ++-- src/client/views/nodes/audio/AudioWaveform.tsx | 2 +- .../views/nodes/formattedText/DashDocView.tsx | 16 ++--- .../views/nodes/formattedText/EquationView.tsx | 4 +- .../views/nodes/formattedText/RichTextMenu.tsx | 16 ++--- .../views/nodes/importBox/ImportElementBox.tsx | 4 +- src/client/views/pdf/Annotation.tsx | 55 ++++++++-------- src/client/views/search/SearchBox.tsx | 10 +-- src/client/views/selectedDoc/SelectedDocView.tsx | 6 +- 47 files changed, 289 insertions(+), 350 deletions(-) (limited to 'src/client/views/nodes/ScriptingBox.tsx') diff --git a/src/client/util/BranchingTrailManager.tsx b/src/client/util/BranchingTrailManager.tsx index 11f16493f..02879e3c4 100644 --- a/src/client/util/BranchingTrailManager.tsx +++ b/src/client/util/BranchingTrailManager.tsx @@ -54,7 +54,7 @@ export class BranchingTrailManager extends React.Component { @observable private docIdToDocMap: Map = new Map(); observeDocumentChange = (targetDoc: Doc, pres: PresBox) => { - const presId = pres.props.Document[Id]; + const presId = pres.Document[Id]; if (this.prevPresId === presId) { return; } diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx index c1e0a5b2e..2e13aff2f 100644 --- a/src/client/util/CaptureManager.tsx +++ b/src/client/util/CaptureManager.tsx @@ -84,7 +84,7 @@ export class CaptureManager extends React.Component<{}> { onClick={() => { const selected = SelectionManager.Views.slice(); SelectionManager.DeselectAll(); - selected.map(dv => dv.props.removeDocument?.(dv.props.Document)); + selected.map(dv => dv.props.removeDocument?.(dv.Document)); this.close(); }}> Cancel diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 039bb360e..82c63695c 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -290,7 +290,7 @@ export namespace DictationManager { if (!ctor) { return false; } - return Cast(Doc.GetProto(view.props.Document).data, ctor) !== undefined; + return Cast(Doc.GetProto(view.Document).data, ctor) !== undefined; }; const validate = (target: DocumentView, types: DocumentType[]) => { @@ -318,7 +318,7 @@ export namespace DictationManager { [ 'clear', { - action: (target: DocumentView) => (Doc.GetProto(target.props.Document).data = new List()), + action: (target: DocumentView) => (Doc.GetProto(target.Document).data = new List()), restrictTo: [DocumentType.COL], }, ], @@ -347,7 +347,7 @@ export namespace DictationManager { action: (target: DocumentView, matches: RegExpExecArray) => { const count = interpretNumber(matches[1]); const what = matches[2]; - const dataDoc = Doc.GetProto(target.props.Document); + const dataDoc = Doc.GetProto(target.Document); const fieldKey = 'data'; if (isNaN(count)) { return; @@ -372,7 +372,7 @@ export namespace DictationManager { expression: /view as (freeform|stacking|masonry|schema|tree)/g, action: (target: DocumentView, matches: RegExpExecArray) => { const mode = matches[1]; - mode && (target.props.Document._type_collection = mode); + mode && (target.Document._type_collection = mode); }, restrictTo: [DocumentType.COL], } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index fe3a52be7..9ede18ed5 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -142,7 +142,7 @@ export namespace DragManager { this.linkSourceGetAnchor = linkSourceGetAnchor; } get dragDocument() { - return this.linkDragView.props.Document; + return this.linkDragView.Document; } linkSourceGetAnchor: () => Doc; linkSourceDoc?: Doc; diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index 7de0f336f..894583711 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -19,35 +19,38 @@ interface GroupMemberViewProps { @observer export class GroupMemberView extends React.Component { @observable private memberSort: 'ascending' | 'descending' | 'none' = 'none'; + get group() { + return this.props.group; + } private get editingInterface() { - let members: string[] = this.props.group ? JSON.parse(StrCast(this.props.group.members)) : []; + let members: string[] = this.group ? JSON.parse(StrCast(this.group.members)) : []; members = this.memberSort === 'ascending' ? members.sort() : this.memberSort === 'descending' ? members.sort().reverse() : members; - const options: UserOptions[] = this.props.group ? GroupManager.Instance.options.filter(option => !(JSON.parse(StrCast(this.props.group.members)) as string[]).includes(option.value)) : []; + const options: UserOptions[] = this.group ? GroupManager.Instance.options.filter(option => !(JSON.parse(StrCast(this.group.members)) as string[]).includes(option.value)) : []; - const hasEditAccess = GroupManager.Instance.hasEditAccess(this.props.group); + const hasEditAccess = GroupManager.Instance.hasEditAccess(this.group); - return !this.props.group ? null : ( + return !this.group ? null : (
(this.props.group.title = e.currentTarget.value)} + value={StrCast(this.group.title || this.group.groupName)} + onChange={e => (this.group.title = e.currentTarget.value)} disabled={!hasEditAccess}>
- {GroupManager.Instance.hasEditAccess(this.props.group) ? ( + {GroupManager.Instance.hasEditAccess(this.group) ? (
diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx index ea99bff2e..c38c6dc4e 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -18,12 +18,8 @@ interface ResizerProps { select: (isCtrlPressed: boolean) => void; } -const resizerOpacity = 1; - @observer export default class ResizeBar extends React.Component { - @observable private isHoverActive = false; - @observable private isResizingActive = false; private _resizeUndo?: UndoManager.Batch; @action @@ -35,7 +31,6 @@ export default class ResizeBar extends React.Component { window.removeEventListener('pointerup', this.onPointerUp); window.addEventListener('pointermove', this.onPointerMove); window.addEventListener('pointerup', this.onPointerUp); - this.isResizingActive = true; this._resizeUndo = UndoManager.StartBatch('multcol resizing'); }; @@ -80,8 +75,6 @@ export default class ResizeBar extends React.Component { @action private onPointerUp = () => { - this.isResizingActive = false; - this.isHoverActive = false; window.removeEventListener('pointermove', this.onPointerMove); window.removeEventListener('pointerup', this.onPointerUp); this._resizeUndo?.end(); @@ -96,9 +89,7 @@ export default class ResizeBar extends React.Component { pointerEvents: this.props.isContentActive?.() ? 'all' : 'none', width: this.props.width, backgroundColor: !this.props.isContentActive?.() ? '' : this.props.styleProvider?.(undefined, undefined, StyleProp.WidgetColor), - }} - onPointerEnter={action(() => (this.isHoverActive = true))} - onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))}> + }}>
this.registerResizing(e)} />
); diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx index 7dee65e58..6f1b3b425 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx @@ -17,12 +17,8 @@ interface ResizerProps { toBottom?: Doc; } -const resizerOpacity = 1; - @observer export default class ResizeBar extends React.Component { - @observable private isHoverActive = false; - @observable private isResizingActive = false; private _resizeUndo?: UndoManager.Batch; @action @@ -33,7 +29,6 @@ export default class ResizeBar extends React.Component { window.removeEventListener('pointerup', this.onPointerUp); window.addEventListener('pointermove', this.onPointerMove); window.addEventListener('pointerup', this.onPointerUp); - this.isResizingActive = true; this._resizeUndo = UndoManager.StartBatch('multcol resizing'); }; @@ -78,8 +73,6 @@ export default class ResizeBar extends React.Component { @action private onPointerUp = () => { - this.isResizingActive = false; - this.isHoverActive = false; window.removeEventListener('pointermove', this.onPointerMove); window.removeEventListener('pointerup', this.onPointerUp); this._resizeUndo?.end(); @@ -94,9 +87,7 @@ export default class ResizeBar extends React.Component { pointerEvents: this.props.isContentActive?.() ? 'all' : 'none', height: this.props.height, backgroundColor: !this.props.isContentActive?.() ? '' : this.props.styleProvider?.(undefined, undefined, StyleProp.WidgetColor), - }} - onPointerEnter={action(() => (this.isHoverActive = true))} - onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))}> + }}>
this.registerResizing(e)} />
); diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index a69f083d1..50a8bf83d 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -358,7 +358,7 @@ export class LineChart extends ObservableReactComponent { const selectedPt = this._currSelected ? `{ ${this._props.axes[0]}: ${this._currSelected.x} ${this._props.axes[1]}: ${this._currSelected.y} }` : 'none'; if (this._lineChartData.length > 0 || !this.parentViz || this.parentViz.length == 0) { return this._props.axes.length >= 2 && /\d/.test(this._props.records[0][this._props.axes[0]]) && /\d/.test(this._props.records[0][this._props.axes[1]]) ? ( -
+
{
) : null} diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index f127fecf3..5365fe1b2 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -169,7 +169,7 @@ export class TableBox extends ObservableReactComponent { return (
{ if (this._props.layoutDoc && e.key === 'a' && (e.ctrlKey || e.metaKey)) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f8f4b94a2..d07824099 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -881,7 +881,7 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; panelHeight = () => this._props.PanelHeight() - this.headerMargin; - screenToLocal = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); + contentScreenToLocal = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler); setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height); setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); @@ -925,7 +925,7 @@ export class DocumentViewInternal extends DocComponent { } @observable _selected = false; - public get SELECTED() { + public get IsSelected() { return this._selected; } - public set SELECTED(val) { + public set IsSelected(val) { runInAction(() => (this._selected = val)); } @observable public static LongPress = false; @@ -1431,9 +1431,9 @@ export class DocumentView extends ObservableReactComponent { return this._props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined; } @computed get hideLinkButton() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HideLinkBtn + (this.SELECTED ? ':selected' : '')); + return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HideLinkBtn + (this.IsSelected ? ':selected' : '')); } - hideLinkCount = () => this._props.renderDepth === -1 || (this.SELECTED && this._props.renderDepth) || !this._isHovering || this.hideLinkButton; + hideLinkCount = () => this._props.renderDepth === -1 || (this.IsSelected && this._props.renderDepth) || !this._isHovering || this.hideLinkButton; @computed get linkCountView() { return ; } @@ -1568,9 +1568,9 @@ export class DocumentView extends ObservableReactComponent { layout_fitWidthFunc = (doc: Doc) => BoolCast(this.layout_fitWidth); scaleToScreenSpace = () => (1 / (this._props.NativeDimScaling?.() || 1)) * this.screenToLocalTransform().Scale; docViewPathFunc = () => this.docViewPath; - isSelected = () => this.SELECTED; + isSelected = () => this.IsSelected; select = (extendSelection: boolean, focusSelection?: boolean) => { - if (this.SELECTED && SelectionManager.Views.length > 1) SelectionManager.DeselectView(this); + if (this.IsSelected && SelectionManager.Views.length > 1) SelectionManager.DeselectView(this); else { SelectionManager.SelectView(this, extendSelection); if (focusSelection) { diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx index 1dbbbb633..722a347f1 100644 --- a/src/client/views/nodes/MapBox/MapBox2.tsx +++ b/src/client/views/nodes/MapBox/MapBox2.tsx @@ -127,7 +127,7 @@ // private _ref: React.RefObject = React.createRef(); // componentDidMount() { -// this.props.setContentView?.(this); +// this._props.setContentView?.(this); // } // @action @@ -358,9 +358,9 @@ // e, // (e, down, delta) => // runInAction(() => { -// const localDelta = this.props +// const localDelta = this._props // .ScreenToLocalTransform() -// .scale(this.props.NativeDimScaling?.() || 1) +// .scale(this._props.NativeDimScaling?.() || 1) // .transformDirection(delta[0], delta[1]); // const fullWidth = NumCast(this.layoutDoc._width); // const mapWidth = fullWidth - this.sidebarWidth(); @@ -380,12 +380,12 @@ // ); // }; -// sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth(); +// sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this._props.PanelWidth(); // @computed get layout_sidebarWidthPercent() { // return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); // } // @computed get sidebarColor() { -// return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4')); +// return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this._props.fieldKey + '_backgroundColor'], '#e4e4e4')); // } // /** @@ -444,7 +444,7 @@ // key="sidebar" // title="Toggle Sidebar" // style={{ -// display: !this.props.isContentActive() ? 'none' : undefined, +// display: !this._props.isContentActive() ? 'none' : undefined, // top: StrCast(this.layoutDoc._layout_showTitle) === 'title' ? 20 : 5, // backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK, // }} @@ -481,7 +481,7 @@ // }; // pointerEvents = () => { -// return this.props.isContentActive() === false ? 'none' : this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.IsDragging ? undefined : 'none'; +// return this._props.isContentActive() === false ? 'none' : this._props.isContentActive() && this._props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.IsDragging ? undefined : 'none'; // }; // @computed get annotationLayer() { // return ( @@ -489,7 +489,7 @@ // {this.inlineTextAnnotations // .sort((a, b) => NumCast(a.y) - NumCast(b.y)) // .map(anno => ( -// +// // ))} //
// ); @@ -515,13 +515,13 @@ // // } // }; -// panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth(); -// panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); -// scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); -// transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter]; -// opaqueFilter = () => [...this.props.childFilters(), Utils.OpaqueBackgroundFilter]; -// infoWidth = () => this.props.PanelWidth() / 5; -// infoHeight = () => this.props.PanelHeight() / 5; +// panelWidth = () => this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth(); +// panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); +// scrollXf = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); +// transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; +// opaqueFilter = () => [...this._props.childFilters(), Utils.OpaqueBackgroundFilter]; +// infoWidth = () => this._props.PanelWidth() / 5; +// infoHeight = () => this._props.PanelHeight() / 5; // anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; // savedAnnotations = () => this._savedAnnotations; @@ -556,7 +556,7 @@ // .map(marker => ( // // () { } get mapBoxView() { - return this.props.DocumentView?.()?._props.docViewPath().lastElement()?.ComponentView as MapBox; + return this._props.DocumentView?.()?._props.docViewPath().lastElement()?.ComponentView as MapBox; } get mapBox() { - return this.props.DocumentView?.()._props.docViewPath().lastElement()?.Document; + return this._props.DocumentView?.()._props.docViewPath().lastElement()?.Document; } render() { diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index 70037f29c..2c31bbab7 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -89,7 +89,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent runInAction(() => { - const localDelta = this.props + const localDelta = this._props .ScreenToLocalTransform() - .scale(this.props.NativeDimScaling?.() || 1) + .scale(this._props.NativeDimScaling?.() || 1) .transformDirection(delta[0], delta[1]); const fullWidth = NumCast(this.layoutDoc._width); const mapWidth = fullWidth - this.sidebarWidth(); @@ -183,7 +183,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar map') ); }; - sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth(); + sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this._props.PanelWidth(); /** * Handles toggle of sidebar on click the little comment button @@ -195,7 +195,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { - e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.Document; + e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this._props.Document; e.annoDragData.linkSourceDoc.followLinkZoom = false; } }, @@ -276,15 +276,15 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent this.addDocument(doc, annotationKey); - pointerEvents = () => (this.props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : 'none'); + pointerEvents = () => (this._props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : 'none'); - panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth(); - panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); - scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); - transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter]; - opaqueFilter = () => [...this.props.childFilters(), Utils.OpaqueBackgroundFilter]; - infoWidth = () => this.props.PanelWidth() / 5; - infoHeight = () => this.props.PanelHeight() / 5; + panelWidth = () => this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth(); + panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); + scrollXf = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); + transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; + opaqueFilter = () => [...this._props.childFilters(), Utils.OpaqueBackgroundFilter]; + infoWidth = () => this._props.PanelWidth() / 5; + infoHeight = () => this._props.PanelHeight() / 5; anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; savedAnnotations = () => this._savedAnnotations; @@ -399,9 +399,9 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { - this.props.select(false); + this._props.select(false); this.deselectPin(); }; /* @@ -677,9 +677,9 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent ( {/* [this.props.PanelWidth(), this.props.PanelHeight()], this.setupSimulation, { fireImmediately: true }); + this._widthDisposer = reaction(() => [this._props.PanelWidth(), this._props.PanelHeight()], this.setupSimulation, { fireImmediately: true }); // Create walls this.wallPositions = [ { length: 100, xPos: 0, yPos: 0, angleInDegrees: 0 }, { length: 100, xPos: 0, yPos: 100, angleInDegrees: 0 }, { length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 }, - { length: 100, xPos: (this.xMax / this.props.PanelWidth()) * 100, yPos: 0, angleInDegrees: 90 }, + { length: 100, xPos: (this.xMax / this._props.PanelWidth()) * 100, yPos: 0, angleInDegrees: 90 }, ]; } - componentDidUpdate(prevProps: Readonly>) { + componentDidUpdate(prevProps: Readonly) { super.componentDidUpdate(prevProps); - if (this.xMax !== this.props.PanelWidth() * 0.6 || this.yMax != this.props.PanelHeight()) { - this.xMax = this.props.PanelWidth() * 0.6; - this.yMax = this.props.PanelHeight(); + if (this.xMax !== this._props.PanelWidth() * 0.6 || this.yMax != this._props.PanelHeight()) { + this.xMax = this._props.PanelWidth() * 0.6; + this.yMax = this._props.PanelHeight(); this.setupSimulation(); } } @@ -632,7 +632,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { - const length = (300 * this.props.PanelWidth()) / 1000; + const length = (300 * this._props.PanelWidth()) / 1000; const angle = 30; const x = length * Math.cos(((90 - angle) * Math.PI) / 180); const y = length * Math.sin(((90 - angle) * Math.PI) / 180); @@ -808,8 +808,8 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
@@ -923,8 +923,8 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
this.props.isContentActive() && e.stopPropagation()} - style={{ overflow: 'auto', height: `${Math.max(1, 800 / this.props.PanelWidth()) * 100}%`, transform: `scale(${Math.min(1, this.props.PanelWidth() / 850)})` }}> + onWheel={e => this._props.isContentActive() && e.stopPropagation()} + style={{ overflow: 'auto', height: `${Math.max(1, 800 / this._props.PanelWidth()) * 100}%`, transform: `scale(${Math.min(1, this._props.PanelWidth() / 850)})` }}>
{this.dataDoc.simulation_paused && this.simulationMode != 'Tutorial' && ( diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx index 658cfb1ca..c04a81f7d 100644 --- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx +++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx @@ -31,7 +31,7 @@ export class RecordingBox extends ViewBoxBaseComponent() { private _ref: React.RefObject = React.createRef(); componentDidMount() { - this.props.setContentView?.(this); + this._props.setContentView?.(this); Doc.SetNativeWidth(this.dataDoc, 1280); Doc.SetNativeHeight(this.dataDoc, 720); } @@ -49,7 +49,7 @@ export class RecordingBox extends ViewBoxBaseComponent() { this.dataDoc[this.fieldKey + '_duration'] = this.videoDuration; this.dataDoc.layout = VideoBox.LayoutString(this.fieldKey); - this.dataDoc[this.props.fieldKey] = new VideoField(this.result.accessPaths.client); + this.dataDoc[this._props.fieldKey] = new VideoField(this.result.accessPaths.client); this.dataDoc[this.fieldKey + '_recorded'] = true; // stringify the presentation and store it if (presentation?.movements) { @@ -135,7 +135,7 @@ export class RecordingBox extends ViewBoxBaseComponent() { @action public static addRecToWorkspace(value: RecordingBox) { let ffView = Array.from(DocumentManager.Instance.DocumentViews).find(view => view.ComponentView instanceof CollectionFreeFormView); - (ffView?.ComponentView as CollectionFreeFormView).props.addDocument?.(value.Document); + (ffView?.ComponentView as CollectionFreeFormView)._props.addDocument?.(value.Document); Doc.RemoveDocFromList(Doc.UserDoc(), 'workspaceRecordings', value.Document); Doc.RemFromMyOverlay(value.Document); Doc.UserDoc().currentRecording = undefined; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 79ed69cdd..36527c311 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -47,8 +47,8 @@ declare class MediaRecorder { // _mesh: any = undefined; // render() { -// const topLeft = [this.props.x, this.props.y]; -// const raised = this.props.raised; +// const topLeft = [this._props.x, this._props.y]; +// const raised = this._props.raised; // const find = (raised: { coord: Vector2, off: Vector3 }[], what: Vector2) => raised.find(r => r.coord.x === what.x && r.coord.y === what.y); // const tl1 = find(raised, new Vector2(topLeft[0], topLeft[1] + 1)); // const tl2 = find(raised, new Vector2(topLeft[0] + 1, topLeft[1] + 1)); @@ -69,11 +69,11 @@ declare class MediaRecorder { // const normals = new Float32Array(quad_normals); // const uvs = new Float32Array(quad_uvs); // Each vertex has one uv coordinate for texture mapping // const indices = new Uint32Array(quad_indices); // Use the four vertices to draw the two triangles that make up the square. -// const popOut = () => NumCast(this.props.Document.popOut); -// const popOff = () => NumCast(this.props.Document.popOff); +// const popOut = () => NumCast(this.Document.popOut); +// const popOff = () => NumCast(this.Document.popOff); // return ( // { -// this.props.setRaised([ +// this._props.setRaised([ // { coord: new Vector2(topLeft[0], topLeft[1]), off: new Vector3(-popOff(), -popOff(), popOut()) }, // { coord: new Vector2(topLeft[0] + 1, topLeft[1]), off: new Vector3(popOff(), -popOff(), popOut()) }, // { coord: new Vector2(topLeft[0], topLeft[1] + 1), off: new Vector3(-popOff(), popOff(), popOut()) }, @@ -99,7 +99,7 @@ declare class MediaRecorder { // r?.setAttribute('uv', new BufferAttribute(uvs, 2)); // r?.setIndex(new BufferAttribute(indices, 1)); // }} /> -// {!this._videoRef ? : +// {!this._videoRef ? : // // // } @@ -118,7 +118,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent ({ width: this.props.PanelWidth(), height: this.props.PanelHeight() }), + this._props.setContentView?.(this); // this tells the DocumentView that this ScreenshotBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link. + // this.layoutDoc.videoWall && reaction(() => ({ width: this._props.PanelWidth(), height: this._props.PanelHeight() }), // ({ width, height }) => { // if (this._camera) { // const angle = -Math.abs(1 - width / height); @@ -201,7 +201,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent numberRange(this._numScreens).forEach(y => screens.push( // ))); - // return { + // return { // this._camera = props.camera; // props.camera.position.set(this._numScreens / 2, this._numScreens / 2, this._numScreens - 2); // props.camera.lookAt(this._numScreens / 2, this._numScreens / 2, 0); @@ -224,15 +224,15 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent { const [{ result }] = await Networking.UploadFilesToServer(aud_chunks.map((file: any) => ({ file }))); if (!(result instanceof Error)) { - this.dataDoc[this.props.fieldKey + '_audio'] = new AudioField(result.accessPaths.agnostic.client); + this.dataDoc[this._props.fieldKey + '_audio'] = new AudioField(result.accessPaths.agnostic.client); } }; this._videoRef!.srcObject = await (navigator.mediaDevices as any).getDisplayMedia({ video: true }); this._videoRec = new MediaRecorder(this._videoRef!.srcObject); const vid_chunks: any = []; this._videoRec.onstart = () => { - if (this.dataDoc[this.props.fieldKey + '_trackScreen']) TrackMovements.Instance.start(); - this.dataDoc[this.props.fieldKey + '_recordingStart'] = new DateField(new Date()); + if (this.dataDoc[this._props.fieldKey + '_trackScreen']) TrackMovements.Instance.start(); + this.dataDoc[this._props.fieldKey + '_recordingStart'] = new DateField(new Date()); }; this._videoRec.ondataavailable = (e: any) => vid_chunks.push(e.data); this._videoRec.onstop = async (e: any) => { @@ -252,7 +252,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent (NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc._height)) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc._width))) * this.props.PanelWidth(); - formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight()); + videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc._height)) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc._width))) * this._props.PanelWidth(); + formattedPanelHeight = () => Math.max(0, this._props.PanelHeight() - this.videoPanelHeight()); render() { TraceMobx(); return ( @@ -296,14 +296,14 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent
+ ScreenToLocalTransform={this._props.ScreenToLocalTransform} + renderDepth={this._props.renderDepth + 1}> <> {this.threed} {this.content} @@ -324,7 +324,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent {!(this.dataDoc[this.fieldKey + '_dictation'] instanceof Doc) ? null : ( )}
- {!this.props.isSelected() ? null : ( + {!this._props.isSelected() ? null : (
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 8e506ec64..73ad3a004 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -60,7 +60,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent !p.startsWith('_')) @@ -116,7 +116,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { @@ -294,7 +294,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { const copy = Doc.MakeCopy(this.Document, true); copy.x = NumCast(this.Document.x) + NumCast(this.dataDoc._width); - this.props.addDocument?.(copy); + this._props.addDocument?.(copy); }; // adds option to create a copy to the context menu @@ -310,7 +310,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent (this.functionName = e.target.value)} placeholder="enter name here" value={this.functionName} />; return ( -
this.props.isSelected() && e.stopPropagation()}> +
this._props.isSelected() && e.stopPropagation()}>
@@ -687,7 +687,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent this.props.isSelected() && e.stopPropagation()}> +
this._props.isSelected() && e.stopPropagation()}>
{this.renderScriptingBox} {definedParameters} @@ -745,7 +745,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent this.props.isSelected() && e.stopPropagation()}> +
this._props.isSelected() && e.stopPropagation()}> {!this.compileParams.length || !this.paramsNames ? null : (
{this.paramsNames.map((parameter: string, i: number) => ( @@ -812,7 +812,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent -
this.props.isSelected() && e.stopPropagation()}> +
this._props.isSelected() && e.stopPropagation()}> {this._paramSuggestion ? (
{' '} diff --git a/src/client/views/nodes/audio/AudioWaveform.tsx b/src/client/views/nodes/audio/AudioWaveform.tsx index 3e46ff4e6..7fd799952 100644 --- a/src/client/views/nodes/audio/AudioWaveform.tsx +++ b/src/client/views/nodes/audio/AudioWaveform.tsx @@ -109,7 +109,7 @@ export class AudioWaveform extends ObservableReactComponent progressColor={Colors.MEDIUM_BLUE_ALT} progress={this._props.progress ?? 1} barWidth={200 / this.audioBuckets.length} - //gradientColors={this.props.gradientColors} + //gradientColors={this._props.gradientColors} peaks={this.audioBuckets} width={(this._props.PanelWidth ?? 0) * window.devicePixelRatio} height={this.waveHeight * window.devicePixelRatio} diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 1002ee403..5a13fa8b4 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -177,7 +177,7 @@ export class DashDocViewInternal extends React.Component { }; componentWillUnmount = () => Object.values(this._disposers).forEach(disposer => disposer?.()); - isContentActive = () => this.props.tbox.props.isSelected() || this.props.tbox.isAnyChildContentActive?.(); + isContentActive = () => this.props.tbox._props.isSelected() || this.props.tbox.isAnyChildContentActive?.(); render() { return !this._dashDoc || !this._finalLayout || this.props.hidden ? null : ( @@ -205,21 +205,21 @@ export class DashDocViewInternal extends React.Component { removeDocument={this.removeDoc} isDocumentActive={returnFalse} isContentActive={this.isContentActive} - styleProvider={this._textBox.props.styleProvider} - docViewPath={this._textBox.props.docViewPath} + styleProvider={this._textBox._props.styleProvider} + docViewPath={this._textBox._props.docViewPath} ScreenToLocalTransform={this.getDocTransform} - addDocTab={this._textBox.props.addDocTab} + addDocTab={this._textBox._props.addDocTab} pinToPres={returnFalse} - renderDepth={this._textBox.props.renderDepth + 1} + renderDepth={this._textBox._props.renderDepth + 1} PanelWidth={this._finalLayout[Width]} PanelHeight={this._finalLayout[Height]} focus={this.outerFocus} whenChildContentsActiveChanged={this.props.tbox.whenChildContentsActiveChanged} bringToFront={emptyFunction} dontRegisterView={false} - childFilters={this.props.tbox?.props.childFilters} - childFiltersByRanges={this.props.tbox?.props.childFiltersByRanges} - searchFilterDocs={this.props.tbox?.props.searchFilterDocs} + childFilters={this.props.tbox?._props.childFilters} + childFiltersByRanges={this.props.tbox?._props.childFiltersByRanges} + searchFilterDocs={this.props.tbox?._props.searchFilterDocs} />
); diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx index 7e655531e..b786c5ffb 100644 --- a/src/client/views/nodes/formattedText/EquationView.tsx +++ b/src/client/views/nodes/formattedText/EquationView.tsx @@ -65,8 +65,8 @@ export class EquationViewInternal extends React.Component constructor(props: any) { super(props); - this._fieldKey = this.props.fieldKey; - this._textBoxDoc = this.props.tbox.props.Document; + this._fieldKey = props.fieldKey; + this._textBoxDoc = props.tbox.Document; } componentWillUnmount() { diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 3b31f2d17..5858c3b11 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -186,7 +186,7 @@ export class RichTextMenu extends AntimodeMenu { // finds font sizes and families in selection getActiveAlignment() { - if (this.view && this.TextView?.props.rootSelected?.()) { + if (this.view && this.TextView?._props.rootSelected?.()) { const path = (this.view.state.selection.$from as any).path; for (let i = path.length - 3; i < path.length && i >= 0; i -= 3) { if (path[i]?.type === this.view.state.schema.nodes.paragraph || path[i]?.type === this.view.state.schema.nodes.heading) { @@ -199,7 +199,7 @@ export class RichTextMenu extends AntimodeMenu { // finds font sizes and families in selection getActiveListStyle() { - if (this.view && this.TextView?.props.rootSelected?.()) { + if (this.view && this.TextView?._props.rootSelected?.()) { const path = (this.view.state.selection.$from as any).path; for (let i = 0; i < path.length; i += 3) { if (path[i].type === this.view.state.schema.nodes.ordered_list) { @@ -219,7 +219,7 @@ export class RichTextMenu extends AntimodeMenu { const activeSizes = new Set(); const activeColors = new Set(); const activeHighlights = new Set(); - if (this.view && this.TextView?.props.rootSelected?.()) { + if (this.view && this.TextView?._props.rootSelected?.()) { const state = this.view.state; const pos = this.view.state.selection.$from; const marks: Mark[] = [...(state.storedMarks ?? [])]; @@ -254,7 +254,7 @@ export class RichTextMenu extends AntimodeMenu { //finds all active marks on selection in given group getActiveMarksOnSelection() { let activeMarks: MarkType[] = []; - if (!this.view || !this.TextView?.props.rootSelected?.()) return activeMarks; + if (!this.view || !this.TextView?._props.rootSelected?.()) return activeMarks; const markGroup = [schema.marks.noAutoLinkAnchor, schema.marks.strong, schema.marks.em, schema.marks.underline, schema.marks.strikethrough, schema.marks.superscript, schema.marks.subscript]; if (this.view.state.storedMarks) return this.view.state.storedMarks.map(mark => mark.type); @@ -447,7 +447,7 @@ export class RichTextMenu extends AntimodeMenu { this.layoutDoc && (this.layoutDoc.layout_centered = !this.layoutDoc.layout_centered); }; align = (view: EditorView, dispatch: any, alignment: 'left' | 'right' | 'center') => { - if (this.TextView?.props.rootSelected?.()) { + if (this.TextView?._props.rootSelected?.()) { var tr = view.state.tr; view.state.doc.nodesBetween(view.state.selection.from, view.state.selection.to, (node, pos, parent, index) => { if ([schema.nodes.paragraph, schema.nodes.heading].includes(node.type)) { @@ -581,7 +581,7 @@ export class RichTextMenu extends AntimodeMenu { return (this.view as any)?.TextView as FormattedTextBox; } get TextViewFieldKey() { - return this.TextView?.props.fieldKey; + return this.TextView?._props.fieldKey; } @action setActiveHighlight(color: string) { @@ -774,11 +774,11 @@ export class RichTextMenu extends AntimodeMenu { //
// {[this.createMarksDropdown(this.activeFontSize, this.fontSizeOptions, "font size", action((val: string) => { // this.activeFontSize = val; - // SelectionManager.Views.map(dv => dv.props.Document._text_fontSize = val); + // SelectionManager.Views.map(dv => dv.Document._text_fontSize = val); // })), // this.createMarksDropdown(this.activeFontFamily, this.fontFamilyOptions, "font family", action((val: string) => { // this.activeFontFamily = val; - // SelectionManager.Views.map(dv => dv.props.Document._text_fontFamily = val); + // SelectionManager.Views.map(dv => dv.Document._text_fontFamily = val); // })), //
, // this.createNodesDropdown(this.activeListType, this.listTypeOptions, "list type", () => ({})), diff --git a/src/client/views/nodes/importBox/ImportElementBox.tsx b/src/client/views/nodes/importBox/ImportElementBox.tsx index b573f7c48..1a92acea1 100644 --- a/src/client/views/nodes/importBox/ImportElementBox.tsx +++ b/src/client/views/nodes/importBox/ImportElementBox.tsx @@ -13,12 +13,12 @@ export class ImportElementBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(ImportElementBox, fieldKey); } - screenToLocalXf = () => this.props.ScreenToLocalTransform().scale(1 * (this.props.NativeDimScaling?.() || 1)); + screenToLocalXf = () => this._props.ScreenToLocalTransform().scale(1 * (this._props.NativeDimScaling?.() || 1)); @computed get mainItem() { return (
Opt; } @observer -export class Annotation extends React.Component { +export class Annotation extends ObservableReactComponent { + constructor(props: any) { + super(props); + makeObservable(this); + } render() { return ( -
- {DocListCast(this.props.anno.text_inlineAnnotations).map(a => ( - +
+ {DocListCast(this._props.anno.text_inlineAnnotations).map(a => ( + ))}
); @@ -38,23 +43,23 @@ interface IRegionAnnotationProps extends IAnnotationProps { pointerEvents?: () => Opt; } @observer -class RegionAnnotation extends React.Component { +class RegionAnnotation extends ObservableReactComponent { private _mainCont: React.RefObject = React.createRef(); @computed get annoTextRegion() { - return Cast(this.props.document.annoTextRegion, Doc, null) || this.props.document; + return Cast(this._props.document.annoTextRegion, Doc, null) || this._props.document; } @undoBatch deleteAnnotation = () => { - const docAnnotations = DocListCast(this.props.dataDoc[this.props.fieldKey]); - this.props.dataDoc[this.props.fieldKey] = new List(docAnnotations.filter(a => a !== this.annoTextRegion)); + const docAnnotations = DocListCast(this._props.dataDoc[this._props.fieldKey]); + this._props.dataDoc[this._props.fieldKey] = new List(docAnnotations.filter(a => a !== this.annoTextRegion)); AnchorMenu.Instance.fadeOut(true); - this.props.select(false); + this._props.select(false); }; @undoBatch - pinToPres = () => this.props.pinToPres(this.annoTextRegion, {}); + pinToPres = () => this._props.pinToPres(this.annoTextRegion, {}); @undoBatch makeTargretToggle = () => (this.annoTextRegion.followLinkToggle = !this.annoTextRegion.followLinkToggle); @@ -65,7 +70,7 @@ class RegionAnnotation extends React.Component { const trail = DocCast(anchor.presentationTrail); if (trail) { Doc.ActivePresentation = trail; - this.props.addDocTab(trail, OpenWhere.replaceRight); + this._props.addDocTab(trail, OpenWhere.replaceRight); } }; @@ -94,9 +99,9 @@ class RegionAnnotation extends React.Component { }; @computed get linkHighlighted() { - for (const link of LinkManager.Instance.getAllDirectLinks(this.props.document)) { - const a1 = LinkManager.getOppositeAnchor(link, this.props.document); - if (a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, this.props.document))) return true; + for (const link of LinkManager.Instance.getAllDirectLinks(this._props.document)) { + const a1 = LinkManager.getOppositeAnchor(link, this._props.document); + if (a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, this._props.document))) return true; } } @@ -107,24 +112,24 @@ class RegionAnnotation extends React.Component { className="htmlAnnotation" ref={this._mainCont} onPointerEnter={action(() => { - Doc.BrushDoc(this.props.anno); - this.props.showInfo?.(this.props.anno); + Doc.BrushDoc(this._props.anno); + this._props.showInfo?.(this._props.anno); })} onPointerLeave={action(() => { - Doc.UnBrushDoc(this.props.anno); - this.props.showInfo?.(undefined); + Doc.UnBrushDoc(this._props.anno); + this._props.showInfo?.(undefined); })} onPointerDown={this.onPointerDown} onContextMenu={this.onContextMenu} style={{ - left: NumCast(this.props.document.x), - top: NumCast(this.props.document.y), - width: NumCast(this.props.document._width), - height: NumCast(this.props.document._height), + left: NumCast(this._props.document.x), + top: NumCast(this._props.document.y), + width: NumCast(this._props.document._width), + height: NumCast(this._props.document._height), opacity: brushed === Doc.DocBrushStatus.highlighted ? 0.5 : undefined, - pointerEvents: this.props.pointerEvents?.() as any, + pointerEvents: this._props.pointerEvents?.() as any, outline: brushed === Doc.DocBrushStatus.unbrushed && this.linkHighlighted ? 'solid 1px lightBlue' : undefined, - backgroundColor: brushed === Doc.DocBrushStatus.highlighted ? 'orange' : StrCast(this.props.document.backgroundColor), + backgroundColor: brushed === Doc.DocBrushStatus.highlighted ? 'orange' : StrCast(this._props.document.backgroundColor), }} /> ); diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 14187833f..4d29573d4 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -122,10 +122,10 @@ export class SearchBox extends ViewBoxBaseComponent() { @undoBatch makeLink = action((linkTo: Doc) => { - const linkFrom = this.props.linkCreateAnchor?.(); + const linkFrom = this._props.linkCreateAnchor?.(); if (linkFrom) { const link = DocUtils.MakeLink(linkFrom, linkTo, {}); - link && this.props.linkCreated?.(link); + link && this._props.linkCreated?.(link); } }); @@ -292,7 +292,7 @@ export class SearchBox extends ViewBoxBaseComponent() { const query = StrCast(this._searchString); Doc.SetSearchQuery(query); - if (!this.props.linkSearch) Array.from(this._results.keys()).forEach(doc => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, true)); + if (!this._props.linkSearch) Array.from(this._results.keys()).forEach(doc => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, true)); this._results.clear(); if (query) { @@ -375,13 +375,13 @@ export class SearchBox extends ViewBoxBaseComponent() { render() { var validResults = 0; - const isLinkSearch: boolean = this.props.linkSearch; + const isLinkSearch: boolean = this._props.linkSearch; const sortedResults = Array.from(this._results.entries()).sort((a, b) => (this._pageRanks.get(b[0]) ?? 0) - (this._pageRanks.get(a[0]) ?? 0)); // sorted by page rank const resultsJSX = Array(); - const fromDoc = this.props.linkFrom?.(); + const fromDoc = this._props.linkFrom?.(); sortedResults.forEach(result => { var className = 'searchBox-results-scroll-view-result'; diff --git a/src/client/views/selectedDoc/SelectedDocView.tsx b/src/client/views/selectedDoc/SelectedDocView.tsx index daacb368b..39e778b76 100644 --- a/src/client/views/selectedDoc/SelectedDocView.tsx +++ b/src/client/views/selectedDoc/SelectedDocView.tsx @@ -1,14 +1,14 @@ +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ListBox } from 'browndash-components'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; -import * as React from 'react'; -import { emptyFunction } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; import { DocumentManager } from '../../util/DocumentManager'; -import { SettingsManager } from '../../util/SettingsManager'; import { DocFocusOptions } from '../nodes/DocumentView'; +import { emptyFunction } from '../../../Utils'; +import { SettingsManager } from '../../util/SettingsManager'; export interface SelectedDocViewProps { selectedDocs: Doc[]; -- cgit v1.2.3-70-g09d2 From af380979349308077e13fc12a2d09255b7f05f28 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 23 Jan 2024 16:11:42 -0500 Subject: reorganization of DocumentView, DocumentViewInternal and FieldView methods and props. fix for selection bug after following a link. migrating to use [DocData] instad of GetProto() --- src/client/documents/Documents.ts | 15 +- src/client/util/CurrentUserUtils.ts | 2 +- src/client/util/DocumentManager.ts | 19 +- src/client/util/DragManager.ts | 7 +- src/client/util/DropConverter.ts | 9 +- src/client/util/HypothesisUtils.ts | 18 +- src/client/util/LinkFollower.ts | 9 +- src/client/util/LinkManager.ts | 12 +- src/client/util/SearchUtil.ts | 155 +-- src/client/util/SettingsManager.tsx | 5 +- src/client/views/DashboardView.tsx | 12 +- src/client/views/DocComponent.tsx | 125 +- src/client/views/DocumentDecorations.tsx | 16 +- src/client/views/InkingStroke.tsx | 14 +- src/client/views/LightboxView.tsx | 2 +- src/client/views/MainView.tsx | 29 +- src/client/views/MarqueeAnnotator.tsx | 9 +- src/client/views/PropertiesView.tsx | 5 +- src/client/views/ScriptBox.tsx | 5 +- src/client/views/SidebarAnnos.tsx | 9 +- src/client/views/StyleProvider.tsx | 12 +- src/client/views/TemplateMenu.tsx | 6 +- .../views/collections/CollectionCalendarView.tsx | 4 +- .../views/collections/CollectionCarousel3DView.tsx | 7 +- .../views/collections/CollectionCarouselView.tsx | 6 +- .../views/collections/CollectionDockingView.tsx | 18 +- src/client/views/collections/CollectionMenu.tsx | 25 +- .../views/collections/CollectionNoteTakingView.tsx | 20 +- .../collections/CollectionStackedTimeline.tsx | 27 +- .../views/collections/CollectionStackingView.tsx | 28 +- src/client/views/collections/CollectionSubView.tsx | 33 +- .../views/collections/CollectionTimeView.tsx | 7 +- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 7 +- src/client/views/collections/TabDocView.tsx | 10 +- src/client/views/collections/TreeView.tsx | 19 +- .../CollectionFreeFormLinkView.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 90 +- .../collections/collectionFreeForm/MarqueeView.tsx | 7 +- .../collectionGrid/CollectionGridView.tsx | 6 +- .../CollectionMulticolumnView.tsx | 4 +- .../CollectionMultirowView.tsx | 4 +- .../collectionMulticolumn/MulticolumnResizer.tsx | 6 +- .../collectionMulticolumn/MultirowResizer.tsx | 6 +- .../collectionSchema/CollectionSchemaView.tsx | 10 +- .../collections/collectionSchema/SchemaRowBox.tsx | 10 +- .../collectionSchema/SchemaTableCell.tsx | 5 +- src/client/views/linking/LinkMenu.tsx | 2 +- src/client/views/linking/LinkMenuGroup.tsx | 12 +- src/client/views/newlightbox/NewLightboxView.tsx | 2 +- src/client/views/nodes/AudioBox.tsx | 15 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 10 +- src/client/views/nodes/ComparisonBox.tsx | 15 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 16 +- src/client/views/nodes/DocumentContentsView.tsx | 29 +- src/client/views/nodes/DocumentIcon.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.tsx | 40 +- src/client/views/nodes/DocumentView.tsx | 1214 ++++++++------------ src/client/views/nodes/EquationBox.tsx | 4 +- src/client/views/nodes/FieldView.tsx | 109 +- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 2 +- src/client/views/nodes/FunctionPlotBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 25 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/KeyValuePair.tsx | 4 +- src/client/views/nodes/LabelBox.tsx | 23 +- src/client/views/nodes/LinkAnchorBox.tsx | 10 +- src/client/views/nodes/LinkBox.tsx | 7 +- src/client/views/nodes/LinkDescriptionPopup.tsx | 31 +- src/client/views/nodes/LinkDocPreview.tsx | 6 +- src/client/views/nodes/MapBox/MapBox.tsx | 16 +- src/client/views/nodes/MapBox/MapBox2.tsx | 12 +- src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx | 5 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 26 +- src/client/views/nodes/PDFBox.tsx | 28 +- .../views/nodes/RecordingBox/RecordingBox.tsx | 12 +- src/client/views/nodes/ScreenshotBox.tsx | 13 +- src/client/views/nodes/ScriptingBox.tsx | 8 +- src/client/views/nodes/VideoBox.tsx | 42 +- src/client/views/nodes/WebBox.tsx | 20 +- src/client/views/nodes/calendarBox/CalendarBox.tsx | 10 +- .../views/nodes/formattedText/DashDocView.tsx | 12 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 45 +- .../views/nodes/importBox/ImportElementBox.tsx | 6 +- src/client/views/nodes/trails/PresBox.tsx | 37 +- src/client/views/nodes/trails/PresElementBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 9 +- src/client/views/search/SearchBox.tsx | 8 +- src/client/views/selectedDoc/SelectedDocView.tsx | 8 +- src/client/views/webcam/DashWebRTCVideo.tsx | 16 +- src/fields/Doc.ts | 52 +- 91 files changed, 1304 insertions(+), 1527 deletions(-) (limited to 'src/client/views/nodes/ScriptingBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 40cffcf45..bcc016391 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -205,6 +205,7 @@ export class DocumentOptions { type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection _type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection title?: STRt = new StrInfo('title of document', true); + title_custom?: BOOLt = new BoolInfo('whether title is a default or has been intentionally set'); caption?: RichTextField; author?: string; // STRt = new StrInfo('creator of document'); // bcz: don't change this. Otherwise, the userDoc's field Infos will have a FieldInfo assigned to its author field which will render it unreadable author_date?: DATEt = new DateInfo('date the document was created', true); @@ -1454,17 +1455,17 @@ export namespace DocUtils { TaskCompletionBox.popupY = showPopup[1] - 33; TaskCompletionBox.taskCompleted = true; - LinkDescriptionPopup.popupX = showPopup[0]; - LinkDescriptionPopup.popupY = showPopup[1]; - LinkDescriptionPopup.descriptionPopup = true; + LinkDescriptionPopup.Instance.popupX = showPopup[0]; + LinkDescriptionPopup.Instance.popupY = showPopup[1]; + LinkDescriptionPopup.Instance.display = true; const rect = document.body.getBoundingClientRect(); - if (LinkDescriptionPopup.popupX + 200 > rect.width) { - LinkDescriptionPopup.popupX -= 190; + if (LinkDescriptionPopup.Instance.popupX + 200 > rect.width) { + LinkDescriptionPopup.Instance.popupX -= 190; TaskCompletionBox.popupX -= 40; } - if (LinkDescriptionPopup.popupY + 100 > rect.height) { - LinkDescriptionPopup.popupY -= 40; + if (LinkDescriptionPopup.Instance.popupY + 100 > rect.height) { + LinkDescriptionPopup.Instance.popupY -= 40; TaskCompletionBox.popupY -= 40; } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 0b15e3add..c4af20b9b 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -275,7 +275,7 @@ export class CurrentUserUtils { {key: "Map", creator: opts => Docs.Create.MapDocument([], opts), opts: { _width: 800, _height: 600, _layout_fitWidth: true, }}, {key: "Screengrab", creator: Docs.Create.ScreenshotDocument, opts: { _width: 400, _height: 200 }}, {key: "WebCam", creator: opts => Docs.Create.WebCamDocument("", opts), opts: { _width: 400, _height: 200, recording:true, isSystem: true, cloneFieldFilter: new List(["isSystem"]) }}, - {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, waitForDoubleClickToClick: 'never'}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}}, + {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title_custom: true, waitForDoubleClickToClick: 'never'}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}}, {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, {key: "DataViz", creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts), opts: { _width: 300, _height: 300 }}, {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeView_HideUnrendered: true}}, diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index e81a99e40..f730d17fe 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,6 +1,7 @@ +import { Howl } from 'howler'; import { action, computed, makeObservable, observable, ObservableSet, observe } from 'mobx'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; -import { AclAdmin, AclEdit, Animation } from '../../fields/DocSymbols'; +import { AclAdmin, AclEdit, Animation, DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { listSpec } from '../../fields/Schema'; import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; @@ -10,13 +11,13 @@ import { CollectionViewType } from '../documents/DocumentTypes'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { TabDocView } from '../views/collections/TabDocView'; import { LightboxView } from '../views/LightboxView'; -import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; +import { FocusViewOptions } from '../views/nodes/FieldView'; import { KeyValueBox } from '../views/nodes/KeyValueBox'; import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox'; import { PresBox } from '../views/nodes/trails'; import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; -import { Howl } from 'howler'; export class DocumentManager { private static _instance: DocumentManager; @@ -135,7 +136,7 @@ export class DocumentManager { }); if (toReturn.length === 0) { DocumentManager.Instance.DocumentViews.forEach(view => { - if (Doc.GetProto(view.Document)?.[Id] === id) { + if (view.Document[DocData]?.[Id] === id) { toReturn.push(view); } }); @@ -236,7 +237,7 @@ export class DocumentManager { // shows a documentView by: // traverses down through the viewPath of contexts to the view: // focusing on each context - public showDocumentView = async (targetDocView: DocumentView, options: DocFocusOptions) => { + public showDocumentView = async (targetDocView: DocumentView, options: FocusViewOptions) => { const docViewPath = [...(targetDocView.containerViewPath?.() ?? []), targetDocView]; let rootContextView = docViewPath.shift(); await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined, focused: false }))); @@ -252,7 +253,7 @@ export class DocumentManager { // and finally restoring the targetDoc to the viewSpec specified by the last document which may either be the targetDoc, or a viewSpec that describes the targetDoc configuration public showDocument = async ( targetDoc: Doc, // document to display - options: DocFocusOptions, // options for how to navigate to target + options: FocusViewOptions, // options for how to navigate to target finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done. ) => { Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, targetDoc); @@ -293,7 +294,7 @@ export class DocumentManager { focusViewsInPath = async ( docView: DocumentView, // - options: DocFocusOptions, + options: FocusViewOptions, iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt; childDocView: Opt; focused: boolean }> ) => { let contextView: DocumentView | undefined; // view containing context that contains target @@ -313,7 +314,7 @@ export class DocumentManager { }; @action - restoreDocView(viewSpec: Opt, docView: DocumentView, options: DocFocusOptions, contextView: Opt, targetDoc: Doc) { + restoreDocView(viewSpec: Opt, docView: DocumentView, options: FocusViewOptions, contextView: Opt, targetDoc: Doc) { if (viewSpec && docView) { //if (docView.ComponentView instanceof FormattedTextBox) //viewSpec !== docView.Document && @@ -337,7 +338,7 @@ export class DocumentManager { } } } -export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) { +export function DocFocusOrOpen(doc: Doc, options: FocusViewOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) { const func = () => { const cv = DocumentManager.Instance.getDocumentView(containingDoc); const dv = DocumentManager.Instance.getDocumentView(doc, cv); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 9ede18ed5..70c40c54e 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -13,6 +13,7 @@ import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; import { SnappingManager } from './SnappingManager'; import { UndoManager } from './UndoManager'; +import { DocData } from '../../fields/DocSymbols'; const { default : { contextMenuZindex } } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'inSame' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove @@ -222,7 +223,7 @@ export namespace DragManager { : docDragData.dropAction === 'add' ? d : docDragData.dropAction === 'proto' - ? Doc.GetProto(d) + ? d[DocData] : docDragData.dropAction === 'copy' ? (await Doc.MakeClone(d)).clone : d @@ -250,9 +251,9 @@ export namespace DragManager { export function StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: Field }, params: string[], initialize: (button: Doc) => void, downX: number, downY: number, options?: DragOptions) { const finishDrag = (e: DragCompleteEvent) => { const bd = Docs.Create.ButtonDocument({ toolTip: title, z: 1, _width: 150, _height: 50, title, onClick: ScriptField.MakeScript(script) }); - params.map(p => Object.keys(vars).indexOf(p) !== -1 && (Doc.GetProto(bd)[p] = new PrefetchProxy(vars[p] as Doc))); // copy all "captured" arguments into document parameterfields + params.map(p => Object.keys(vars).indexOf(p) !== -1 && (bd[DocData][p] = new PrefetchProxy(vars[p] as Doc))); // copy all "captured" arguments into document parameterfields initialize?.(bd); - Doc.GetProto(bd)['onClick-paramFieldKeys'] = new List(params); + bd[DocData]['onClick-paramFieldKeys'] = new List(params); e.docDragData && (e.docDragData.droppedDocuments = [bd]); return e; }; diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index 2c371f28e..f62ec8f83 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -1,4 +1,5 @@ import { Doc, DocListCast, Opt } from '../../fields/Doc'; +import { DocData } from '../../fields/DocSymbols'; import { ObjectField } from '../../fields/ObjectField'; import { RichTextField } from '../../fields/RichTextField'; import { listSpec } from '../../fields/Schema'; @@ -12,7 +13,7 @@ import { DragManager } from './DragManager'; import { ScriptingGlobals } from './ScriptingGlobals'; export function MakeTemplate(doc: Doc, first: boolean = true, rename: Opt = undefined, templateField: string = '') { - if (templateField) Doc.GetProto(doc).title = templateField; /// the title determines which field is being templated + if (templateField) doc[DocData].title = templateField; /// the title determines which field is being templated doc.isTemplateDoc = makeTemplate(doc, first, rename); return doc; } @@ -33,7 +34,7 @@ function makeTemplate(doc: Doc, first: boolean = true, rename: Opt = und let any = false; docs.forEach(d => { if (!StrCast(d.title).startsWith('-')) { - any = Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(layoutDoc)) || any; + any = Doc.MakeMetadataFieldTemplate(d, layoutDoc[DocData]) || any; } else if (d.type === DocumentType.COL || d.data instanceof RichTextField) { any = makeTemplate(d, false) || any; } @@ -41,12 +42,12 @@ function makeTemplate(doc: Doc, first: boolean = true, rename: Opt = und if (first) { if (!docs.length) { // bcz: feels hacky : if the root level document has items, it's not a field template - any = Doc.MakeMetadataFieldTemplate(doc, Doc.GetProto(layoutDoc)) || any; + any = Doc.MakeMetadataFieldTemplate(doc, layoutDoc[DocData]) || any; } } if (layoutDoc[fieldKey] instanceof RichTextField || layoutDoc[fieldKey] instanceof ImageField) { if (!StrCast(layoutDoc.title).startsWith('-')) { - any = Doc.MakeMetadataFieldTemplate(layoutDoc, Doc.GetProto(layoutDoc)); + any = Doc.MakeMetadataFieldTemplate(layoutDoc, layoutDoc[DocData]); } } rename && (doc.title = rename); diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts index f46c2d431..c5f307f44 100644 --- a/src/client/util/HypothesisUtils.ts +++ b/src/client/util/HypothesisUtils.ts @@ -30,15 +30,15 @@ export namespace Hypothesis { if (currentDoc && Cast(currentDoc.data, WebField)?.url.href === uri) return currentDoc; // always check first whether the currently selected doc is the annotation's source, only use Search otherwise const results: Doc[] = []; - await SearchUtil.Search('web', true).then( - action(async (res: SearchUtil.DocSearchResult) => { - const docs = res.docs; - const filteredDocs = docs.filter(doc => doc.author === Doc.CurrentUserEmail && doc.type === DocumentType.WEB && doc.data); - filteredDocs.forEach(doc => { - uri === Cast(doc.data, WebField)?.url.href && results.push(doc); // TODO check visited sites history? - }); - }) - ); + // await SearchUtil.Search('web', true).then( + // action(async (res: SearchUtil.DocSearchResult) => { + // const docs = res.docs; + // const filteredDocs = docs.filter(doc => doc.author === Doc.CurrentUserEmail && doc.type === DocumentType.WEB && doc.data); + // filteredDocs.forEach(doc => { + // uri === Cast(doc.data, WebField)?.url.href && results.push(doc); // TODO check visited sites history? + // }); + // }) + // ); const onScreenResults = results.filter(doc => DocumentManager.Instance.getFirstDocumentView(doc)); return onScreenResults.length ? onScreenResults[0] : results.length ? results[0] : undefined; // prioritize results that are currently on the screen diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 2df4d1ca8..20261859c 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -1,16 +1,17 @@ -import { action, observable, runInAction } from 'mobx'; +import { action, runInAction } from 'mobx'; import { Doc, DocListCast, Field, FieldResult, Opt } from '../../fields/Doc'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../fields/Types'; import { DocumentType } from '../documents/DocumentTypes'; -import { DocFocusOptions, OpenWhere } from '../views/nodes/DocumentView'; +import { OpenWhere } from '../views/nodes/DocumentView'; +import { FocusViewOptions } from '../views/nodes/FieldView'; import { PresBox } from '../views/nodes/trails'; import { DocumentManager } from './DocumentManager'; import { LinkManager } from './LinkManager'; import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; -import { UndoManager } from './UndoManager'; import { SnappingManager } from './SnappingManager'; +import { UndoManager } from './UndoManager'; /* * link doc: * - link_anchor_1: doc @@ -72,7 +73,7 @@ export class LinkFollower { if (target) { const doFollow = (canToggle?: boolean) => { const toggleTarget = canToggle && BoolCast(sourceDoc.followLinkToggle); - const options: DocFocusOptions = { + const options: FocusViewOptions = { playAudio: BoolCast(srcAnchor.followLinkAudio), playMedia: BoolCast(srcAnchor.followLinkVideo), toggleTarget, diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index ccb3c6b98..353f28a92 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -1,7 +1,7 @@ import { action, makeObservable, observable, observe, runInAction } from 'mobx'; import { computedFn } from 'mobx-utils'; import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../fields/Doc'; -import { DirectLinks } from '../../fields/DocSymbols'; +import { DirectLinks, DocData } from '../../fields/DocSymbols'; import { FieldLoader } from '../../fields/FieldLoader'; import { List } from '../../fields/List'; import { ProxyField } from '../../fields/Proxy'; @@ -58,8 +58,8 @@ export class LinkManager { link && action(lAnchProtoProtos => { Doc.AddDocToList(Doc.UserDoc(), 'links', link); - lAnchs[0] && Doc.GetProto(lAnchs[0])[DirectLinks].add(link); - lAnchs[1] && Doc.GetProto(lAnchs[1])[DirectLinks].add(link); + lAnchs[0] && lAnchs[0][DocData][DirectLinks].add(link); + lAnchs[1] && lAnchs[1][DocData][DirectLinks].add(link); }) ) ) @@ -74,8 +74,8 @@ export class LinkManager { Promise.all(lAnchs.map(lAnch => PromiseValue(lAnch?.proto as Doc))).then((lAnchProtos: Opt[]) => Promise.all(lAnchProtos.map(lAnchProto => PromiseValue(lAnchProto?.proto as Doc))).then( action(lAnchProtoProtos => { - link && lAnchs[0] && Doc.GetProto(lAnchs[0])[DirectLinks].delete(link); - link && lAnchs[1] && Doc.GetProto(lAnchs[1])[DirectLinks].delete(link); + link && lAnchs[0] && lAnchs[0][DocData][DirectLinks].delete(link); + link && lAnchs[1] && lAnchs[1][DocData][DirectLinks].delete(link); }) ) ) @@ -162,7 +162,7 @@ export class LinkManager { return this.relatedLinker(anchor); } // finds all links that contain the given anchor public getAllDirectLinks(anchor?: Doc): Doc[] { - return anchor ? Array.from(Doc.GetProto(anchor)[DirectLinks]) : []; + return anchor ? Array.from(anchor[DirectLinks]) : []; } // finds all links that contain the given anchor relatedLinker = computedFn(function relatedLinker(this: any, anchor: Doc): Doc[] { diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index e51770c25..2cc64f415 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -1,10 +1,7 @@ -import * as rp from 'request-promise'; -import { DocServer } from '../DocServer'; import { Doc, DocListCast, Field, Opt } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; -import { Utils } from '../../Utils'; -import { DocumentType } from '../documents/DocumentTypes'; import { StrCast } from '../../fields/Types'; +import { DocumentType } from '../documents/DocumentTypes'; export namespace SearchUtil { export type HighlightingResult = { [id: string]: { [key: string]: string[] } }; @@ -110,154 +107,4 @@ export namespace SearchUtil { depth++; } } - export interface IdSearchResult { - ids: string[]; - lines: string[][]; - numFound: number; - highlighting: HighlightingResult | undefined; - } - - export interface DocSearchResult { - docs: Doc[]; - lines: string[][]; - numFound: number; - highlighting: HighlightingResult | undefined; - } - - export interface SearchParams { - hl?: string; - 'hl.fl'?: string; - start?: number; - rows?: number; - fq?: string; - sort?: string; - allowEmbeddings?: boolean; - onlyEmbeddings?: boolean; - facet?: string; - 'facet.field'?: string; - } - export function Search(query: string, returnDocs: true, options?: SearchParams): Promise; - export function Search(query: string, returnDocs: false, options?: SearchParams): Promise; - export async function Search(query: string, returnDocs: boolean, options: SearchParams = {}) { - query = query || '*'; //If we just have a filter query, search for * as the query - const rpquery = Utils.prepend('/dashsearch'); - let replacedQuery = query.replace(/type_t:([^ )])/g, (substring, arg) => `{!join from=id to=proto_i}*:* AND ${arg}`); - if (options.onlyEmbeddings) { - const header = query.match(/_[atnb]?:/) ? replacedQuery : 'DEFAULT:' + replacedQuery; - replacedQuery = `{!join from=id to=proto_i}* AND ${header}`; - } - //console.log("Q: " + replacedQuery + " fq: " + options.fq); - const gotten = await rp.get(rpquery, { qs: { ...options, q: replacedQuery } }); - const result: IdSearchResult = gotten.startsWith('<') ? { ids: [], docs: [], numFound: 0, lines: [] } : JSON.parse(gotten); - if (!returnDocs) { - return result; - } - - const { ids, highlighting } = result; - - const txtresult = - query !== '*' && - JSON.parse( - await rp.get(Utils.prepend('/textsearch'), { - qs: { ...options, q: query.replace(/^[ \+\?\*\|]*/, '') }, // a leading '+' leads to a server crash since findInFiles doesn't handle regex failures - }) - ); - - const fileids = txtresult ? txtresult.ids : []; - const newIds: string[] = []; - const newLines: string[][] = []; - // bcz: we stopped storing fileUpload id's, so this won't find anything - // if (fileids) { - // await Promise.all( - // fileids.map(async (tr: string, i: number) => { - // const docQuery = 'fileUpload_t:' + tr.substr(0, 7); //If we just have a filter query, search for * as the query - // const docResult = JSON.parse(await rp.get(Utils.prepend('/dashsearch'), { qs: { ...options, q: docQuery } })); - // newIds.push(...docResult.ids); - // newLines.push(...docResult.ids.map((dr: any) => txtresult.lines[i])); - // }) - // ); - // } - - const theDocs: Doc[] = []; - const theLines: string[][] = []; - const textDocMap = await DocServer.GetRefFields(newIds); - const textDocs = newIds.map((id: string) => textDocMap[id]).map(doc => doc as Doc); - for (let i = 0; i < textDocs.length; i++) { - const testDoc = textDocs[i]; - if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1) { - theDocs.push(Doc.GetProto(testDoc)); - theLines.push(newLines[i].map(line => line.replace(query, query.toUpperCase()))); - } - } - - const docMap = await DocServer.GetRefFields(ids); - const docs = ids.map((id: string) => docMap[id]).map(doc => doc as Doc); - for (let i = 0; i < ids.length; i++) { - const testDoc = docs[i]; - if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && (options.allowEmbeddings || testDoc.proto === undefined || theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1)) { - theDocs.push(testDoc); - theLines.push([]); - } else { - result.numFound--; - } - } - - return { docs: theDocs, numFound: Math.max(0, result.numFound), highlighting, lines: theLines }; - } - - export async function GetEmbeddingsOfDocument(doc: Doc): Promise; - export async function GetEmbeddingsOfDocument(doc: Doc, returnDocs: false): Promise; - export async function GetEmbeddingsOfDocument(doc: Doc, returnDocs = true): Promise { - const proto = Doc.GetProto(doc); - const protoId = proto[Id]; - if (returnDocs) { - return (await Search('', returnDocs, { fq: `proto_i:"${protoId}"`, allowEmbeddings: true })).docs; - } else { - return (await Search('', returnDocs, { fq: `proto_i:"${protoId}"`, allowEmbeddings: true })).ids; - } - // return Search(`{!join from=id to=proto_i}id:${protoId}`, true); - } - - export async function GetViewsOfDocument(doc: Doc): Promise { - const results = await Search('', true, { fq: `proto_i:"${doc[Id]}"` }); - return results.docs; - } - - export async function GetContextsOfDocument(doc: Doc): Promise<{ contexts: Doc[]; embeddingContexts: Doc[] }> { - const docContexts = (await Search('', true, { fq: `data_l:"${doc[Id]}"` })).docs; - const embeddings = await GetEmbeddingsOfDocument(doc, false); - const embeddingContexts = await Promise.all(embeddings.map(doc => Search('', true, { fq: `data_l:"${doc}"` }))); - const contexts = { contexts: docContexts, embeddingContexts: [] as Doc[] }; - embeddingContexts.forEach(result => contexts.embeddingContexts.push(...result.docs)); - return contexts; - } - - export async function GetContextIdsOfDocument(doc: Doc): Promise<{ contexts: string[]; embeddingContexts: string[] }> { - const docContexts = (await Search('', false, { fq: `data_l:"${doc[Id]}"` })).ids; - const embeddings = await GetEmbeddingsOfDocument(doc, false); - const embeddingContexts = await Promise.all(embeddings.map(doc => Search('', false, { fq: `data_l:"${doc}"` }))); - const contexts = { contexts: docContexts, embeddingContexts: [] as string[] }; - embeddingContexts.forEach(result => contexts.embeddingContexts.push(...result.ids)); - return contexts; - } - - export async function GetAllDocs() { - const query = '*'; - const response = await rp.get(Utils.prepend('/dashsearch'), { - qs: { start: 0, rows: 10000, q: query }, - }); - const result: IdSearchResult = JSON.parse(response); - const { ids, numFound, highlighting } = result; - const docMap = await DocServer.GetRefFields(ids); - const docs: Doc[] = []; - for (const id of ids) { - const field = docMap[id]; - if (field instanceof Doc) { - docs.push(field); - } - } - return docs; - // const docs = ids.map((id: string) => docMap[id]).filter((doc: any) => doc instanceof Doc); - // return docs as Doc[]; - } } diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 0233c4051..5bf9e5b00 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -5,13 +5,13 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { BsGoogle } from 'react-icons/bs'; import { FaFillDrip, FaPalette } from 'react-icons/fa'; +import { Utils, addStyleSheet, addStyleSheetRule } from '../../Utils'; import { Doc, Opt } from '../../fields/Doc'; import { DashVersion } from '../../fields/DocSymbols'; import { BoolCast, Cast, NumCast, StrCast } from '../../fields/Types'; -import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils'; -import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; import { Networking } from '../Network'; +import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { GestureOverlay } from '../views/GestureOverlay'; import { MainViewModal } from '../views/MainViewModal'; import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox'; @@ -47,7 +47,6 @@ export class SettingsManager extends React.Component<{}> { @observable activeTab = 'Accounts'; @observable public propertiesWidth: number = 0; - @observable public headerBarHeight: number = 0; constructor(props: {}) { super(props); diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 523721b84..472d419fc 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -5,7 +5,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { FaPlus } from 'react-icons/fa'; import { Doc, DocListCast } from '../../fields/Doc'; -import { AclPrivate, DocAcl } from '../../fields/DocSymbols'; +import { AclPrivate, DocAcl, DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; import { PrefetchProxy } from '../../fields/Proxy'; @@ -64,7 +64,7 @@ export class DashboardView extends ObservableReactComponent<{}> { getDashboards = (whichGroup: DashboardGroup) => { if (whichGroup === DashboardGroup.MyDashboards) { - return DocListCast(Doc.MyDashboards.data).filter(dashboard => Doc.GetProto(dashboard).author === Doc.CurrentUserEmail); + return DocListCast(Doc.MyDashboards.data).filter(dashboard => dashboard[DocData].author === Doc.CurrentUserEmail); } return DocListCast(Doc.MySharedDocs.data_dashboards).filter(doc => doc.dockingConfig); }; @@ -171,7 +171,7 @@ export class DashboardView extends ObservableReactComponent<{}> { } />
- (Doc.GetProto(dashboard).title = val)} /> + (dashboard[DocData].title = val)} /> {this.selectedDashboardGroup === DashboardGroup.SharedDashboards && this.isUnviewedSharedDashboard(dashboard) ?
unviewed
:
}
{ }, ], }; - if (dashboard.dockingConfig && dashboard.dockingConfig !== Doc.GetProto(dashboard).dockingConfig) dashboard.dockingConfig = JSON.stringify(reset); + if (dashboard.dockingConfig && dashboard.dockingConfig !== dashboard[DocData].dockingConfig) dashboard.dockingConfig = JSON.stringify(reset); else Doc.SetInPlace(dashboard, 'dockingConfig', JSON.stringify(reset), true); return reset; }; @@ -391,9 +391,9 @@ export class DashboardView extends ObservableReactComponent<{}> { Doc.ActivePresentation = undefined; }; - public static SetupDashboardCalendars(dashboardDoc: Doc){ + public static SetupDashboardCalendars(dashboardDoc: Doc) { // this section is creating the button document itself === myTrails = new Button - + // create a a list of calendars (as a CalendarCollectionDocument) and store it on the new dashboard const reqdOpts: DocumentOptions = { title: 'My Calendars', diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 6aba4a042..0e5a4f013 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -2,22 +2,62 @@ import { action, computed, makeObservable, observable } from 'mobx'; import * as React from 'react'; import { returnFalse } from '../../Utils'; import { DateField } from '../../fields/DateField'; -import { Doc, DocListCast, Opt } from '../../fields/Doc'; +import { Doc, DocListCast, Field, Opt } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocData } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; import { GetEffectiveAcl, inheritParentAcls } from '../../fields/util'; import { DocumentType } from '../documents/DocumentTypes'; import { DocUtils } from '../documents/Documents'; import { DocumentManager } from '../util/DocumentManager'; -import { Transform } from '../util/Transform'; import { ObservableReactComponent } from './ObservableReactComponent'; import { CollectionFreeFormView } from './collections/collectionFreeForm'; -import { DocumentView } from './nodes/DocumentView'; +import { FieldViewProps, FocusViewOptions } from './nodes/FieldView'; +import { DocumentView, OpenWhere } from './nodes/DocumentView'; +import { PinProps } from './nodes/trails'; +import { RefField } from '../../fields/RefField'; /** - * DocComponent returns a generic React base class used by Doc views (not the 'Box' views that render the contents of Doc views) - * (e.g.,CollectionFreeFormDocumentView, DocumentViewInternal) - * + * Shared interface among all viewBox'es (ie, react classes that render the contents of a Doc) + * Many of these methods only make sense for specific viewBox'es, but they should be written to + * be as general as possible + */ +export interface ViewBoxInterface { + fieldKey?: string; + annotationKey?: string; + updateIcon?: () => void; // updates the icon representation of the document + getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) + restoreView?: (viewSpec: Doc) => boolean; + scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: FocusViewOptions) => Opt; // returns the duration of the focus + brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number, holdTime: number) => void; // highlight a region of a view (used by freeforms) + getView?: (doc: Doc, options: FocusViewOptions) => Promise>; // returns a nested DocumentView for the specified doc or undefined + addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox + addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections) + select?: (ctrlKey: boolean, shiftKey: boolean) => void; + focus?: (textAnchor: Doc, options: FocusViewOptions) => Opt; + isAnyChildContentActive?: () => boolean; // is any child content of the document active + onClickScriptDisable?: () => 'never' | 'always'; // disable click scripts : never, always, or undefined = only when selected + getKeyFrameEditing?: () => boolean; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown) + setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown) + playFrom?: (time: number, endTime?: number) => void; + Pause?: () => void; // pause a media document (eg, audio/video) + IsPlaying?: () => boolean; // is a media document playing + TogglePause?: (keep?: boolean) => void; // toggle media document playing state + setFocus?: () => void; // sets input focus to the componentView + setData?: (data: Field | Promise) => boolean; + componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null; + dragStarting?: (snapToDraggedDoc: boolean, showGroupDragTarget: boolean, visited: Set) => void; + incrementalRendering?: () => void; + infoUI?: () => JSX.Element | null; + screenBounds?: () => Opt<{ left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } }>; + ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; + ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; + snapPt?: (pt: { X: number; Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number; Y: number }; distance: number }; + search?: (str: string, bwd?: boolean, clear?: boolean) => boolean; +} +/** + * DocComponent returns a React base class used by Doc views with accessors for unpacking he Document,layoutDoc, and dataDoc's + * (note: this should not be used for the 'Box' views that render the contents of Doc views) + * Example derived views: CollectionFreeFormDocumentView, DocumentView, DocumentViewInternal) * */ export interface DocComponentProps { Document: Doc; @@ -26,7 +66,7 @@ export interface DocComponentProps { } export function DocComponent

() { class Component extends ObservableReactComponent> { - constructor(props: any) { + constructor(props: P) { super(props); makeObservable(this); } @@ -41,28 +81,25 @@ export function DocComponent

() { } // This is the data part of a document -- ie, the data that is constant across all views of the document @computed get dataDoc() { - return this._props.Document[DocData]; + return this.Document[DocData]; } } return Component; } /** - * ViewBoxBaseComponent - base class for non-annotatable views that render the interior contents of a DocumentView - * (e.g. InkingStroke, ColorBox) + * base class for non-annotatable views that render the interior contents of a DocumentView. + * this unpacks the Document/layout/data docs as well as the fieldKey being rendered, + * and provides accessors for DocumentView and ScreenToLocalBoxXf + * Example views include: InkingStroke, FontIconBox, EquationBox, etc */ -export interface ViewBoxBaseProps { - Document: Doc; - TemplateDataDocument?: Doc; - DocumentView?: () => DocumentView; - fieldKey: string; - isSelected: () => boolean; - isContentActive: () => boolean | undefined; - ScreenToLocalTransform: () => Transform; - renderDepth: number; -} -export function ViewBoxBaseComponent

() { +export function ViewBoxBaseComponent

() { class Component extends ObservableReactComponent> { + constructor(props: P) { + super(props); + makeObservable(this); + } + ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); get DocumentView() { @@ -89,36 +126,27 @@ export function ViewBoxBaseComponent

() { } /** - * DocAnnotatableComponent - base class for annotatable views that render the interior contents of a DocumentView - * (e.g., PdfBox, ImageBox) - * These views should be interactive (respond to pointerEvents) when their conatainer DocumentView is selected + * base class for annotatable views that render the interior contents of a DocumentView + * This does what ViewBoxBaseComponent does and additionally provides accessor for the + * field key where annotations are stored as well as add/move/remove methods for handing + * annotations. + * This also provides methods to determine when the contents should be interactive + * (respond to pointerEvents) such as when the DocumentView container is selected or a + * peer child of the container is selected + * Example views include: PDFBox, ImageBox, MapBox, etc */ -export interface ViewBoxAnnotatableProps { - Document: Doc; - TemplateDataDocument?: Doc; - DocumentView?: () => DocumentView; - fieldKey: string; - filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) - isContentActive: () => boolean | undefined; - select: (isCtrlPressed: boolean) => void; - whenChildContentsActiveChanged: (isActive: boolean) => void; - ScreenToLocalTransform: () => Transform; - isSelected: () => boolean; - renderDepth: number; - isAnnotationOverlay?: boolean; -} -export function ViewBoxAnnotatableComponent

() { +export function ViewBoxAnnotatableComponent

() { class Component extends ObservableReactComponent> { - constructor(props: any) { + @observable _annotationKeySuffix = () => 'annotations'; + @observable _isAnyChildContentActive = false; + + constructor(props: P) { super(props); makeObservable(this); } ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); - @observable _annotationKeySuffix = () => 'annotations'; - @observable _isAnyChildContentActive = false; - get DocumentView() { return this._props.DocumentView; } @@ -139,9 +167,6 @@ export function ViewBoxAnnotatableComponent

() @computed get fieldKey() { return this._props.fieldKey; } - - isAnyChildContentActive = () => this._isAnyChildContentActive; - @computed public get annotationKey() { return this.fieldKey + (this._annotationKeySuffix() ? '_' + this._annotationKeySuffix() : ''); } @@ -162,7 +187,7 @@ export function ViewBoxAnnotatableComponent

() toRemove.forEach(doc => { leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey); Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc); - Doc.RemoveDocFromList(Doc.GetProto(doc), 'proto_embeddings', doc); + Doc.RemoveDocFromList(doc[DocData], 'proto_embeddings', doc); doc.embedContainer = undefined; if (recent) { doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true); @@ -210,8 +235,8 @@ export function ViewBoxAnnotatableComponent

() if ([AclAugment, AclEdit, AclAdmin].includes(effectiveAcl)) { added.forEach(doc => { doc._dragOnlyWithinContainer = undefined; - if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.Document; - else Doc.GetProto(doc).annotationOn = undefined; + if (annotationKey ?? this._annotationKeySuffix()) doc[DocData].annotationOn = this.Document; + else doc[DocData].annotationOn = undefined; Doc.SetContainer(doc, this.Document); inheritParentAcls(targetDataDoc, doc, true); }); @@ -225,6 +250,8 @@ export function ViewBoxAnnotatableComponent

() return true; }; + isAnyChildContentActive = () => this._isAnyChildContentActive; + whenChildContentsActiveChanged = action((isActive: boolean) => this._props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive))); } return Component; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 8db972ef0..5ef62b2c5 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -8,7 +8,7 @@ import { FaUndo } from 'react-icons/fa'; import { Utils, emptyFunction, lightOrDark, numberValue, returnFalse, setupMoveUpEvents } from '../../Utils'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc'; -import { AclAdmin, AclAugment, AclEdit } from '../../fields/DocSymbols'; +import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols'; import { InkField } from '../../fields/InkField'; import { RichTextField } from '../../fields/RichTextField'; import { ScriptField } from '../../fields/ScriptField'; @@ -101,7 +101,7 @@ export class DocumentDecorations extends ObservableReactComponent dv._props.renderDepth > 0) - .map(dv => dv.getBounds()) + .map(dv => dv.getBounds) .reduce((bounds, rect) => !rect ? bounds : { x: Math.min(rect.left, bounds.x), y: Math.min(rect.top, bounds.y), @@ -203,7 +203,7 @@ export class DocumentDecorations extends ObservableReactComponent(); SelectionManager.Views.forEach(v => containers.add(DocCast(v.Document.embedContainer))); if (containers.size > 1) return false; - const { left, top } = dragDocView.getBounds() || { left: 0, top: 0 }; + const { left, top } = dragDocView.getBounds || { left: 0, top: 0 }; const dragData = new DragManager.DocumentDragData( SelectionManager.Views.map(dv => dv.Document), dragDocView._props.dropAction @@ -541,17 +541,17 @@ export class DocumentDecorations extends ObservableReactComponent ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => { - Doc.GetProto(doc).data = new InkField(inkPts.map( + doc[DocData].data = new InkField(inkPts.map( (ipt) => ({// (new x — oldx) + newWidth * (oldxpoint /oldWidth) X: NumCast(doc.x) - x + (NumCast(doc.width) * ipt.X) / width, Y: NumCast(doc.y) - y + (NumCast(doc.height) * ipt.Y) / height, diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 11b05352d..92644d3c5 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -34,21 +34,19 @@ import { InteractionUtils } from '../util/InteractionUtils'; import { SnappingManager } from '../util/SnappingManager'; import { UndoManager } from '../util/UndoManager'; import { ContextMenu } from './ContextMenu'; -import { ViewBoxBaseComponent, ViewBoxBaseProps } from './DocComponent'; +import { ViewBoxBaseComponent, ViewBoxInterface } from './DocComponent'; import { Colors } from './global/globalEnums'; import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles'; import './InkStroke.scss'; import { InkStrokeProperties } from './InkStrokeProperties'; import { InkTangentHandles } from './InkTangentHandles'; -import { DocComponentView } from './nodes/DocumentView'; import { FieldView, FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { PinProps, PresBox } from './nodes/trails'; import { StyleProp } from './StyleProvider'; -import { Transform } from '../util/Transform'; const { default: { INK_MASK_SIZE } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore @observer -export class InkingStroke extends ViewBoxBaseComponent() { +export class InkingStroke extends ViewBoxBaseComponent() implements ViewBoxInterface { static readonly MaskDim = INK_MASK_SIZE; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big) public static LayoutString(fieldStr: string) { return FieldView.LayoutString(InkingStroke, fieldStr); @@ -64,7 +62,7 @@ export class InkingStroke extends ViewBoxBaseComponent this._props.isSelected(), // react to stroke being deselected by turning off ink handles selected => !selected && (InkStrokeProperties.Instance._controlButton = false) @@ -332,8 +330,8 @@ export class InkingStroke extends ViewBoxBaseComponent (this._subContentView = doc); + _subContentView: ViewBoxInterface | undefined; + setSubContentView = (doc: ViewBoxInterface) => (this._subContentView = doc); @computed get fillColor() { const isInkMask = BoolCast(this.layoutDoc.stroke_isInkMask); return isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FillColor) ?? 'transparent'; @@ -462,7 +460,7 @@ export class InkingStroke extends ViewBoxBaseComponent { addDocTab={this.AddDocTab} pinToPres={TabDocView.PinDoc} bringToFront={emptyFunction} - onBrowseClick={DocumentView.exploreMode} + onBrowseClickScript={DocumentView.exploreMode} focus={emptyFunction} /> diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index d700ea020..9061e98d4 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -15,6 +15,7 @@ import { DocServer } from '../DocServer'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { Docs } from '../documents/Documents'; +import { CalendarManager } from '../util/CalendarManager'; import { CaptureManager } from '../util/CaptureManager'; import { DocumentManager } from '../util/DocumentManager'; import { DragManager } from '../util/DragManager'; @@ -31,7 +32,6 @@ import { SnappingManager } from '../util/SnappingManager'; import { Transform } from '../util/Transform'; import { ReportManager } from '../util/reportManager/ReportManager'; import { ComponentDecorations } from './ComponentDecorations'; -import { SchemaCSVPopUp } from './nodes/DataVizBox/SchemaCSVPopUp'; import { ContextMenu } from './ContextMenu'; import { DashboardView } from './DashboardView'; import { DictationOverlay } from './DictationOverlay'; @@ -55,11 +55,13 @@ import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOpti import { CollectionLinearView } from './collections/collectionLinear'; import { LinkMenu } from './linking/LinkMenu'; import { AudioBox } from './nodes/AudioBox'; +import { SchemaCSVPopUp } from './nodes/DataVizBox/SchemaCSVPopUp'; import { DocButtonState } from './nodes/DocumentLinksButton'; import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from './nodes/DocumentView'; import { ImageBox } from './nodes/ImageBox'; import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; import { LinkDocPreview, LinkInfo } from './nodes/LinkDocPreview'; +import { DirectionsAnchorMenu } from './nodes/MapBox/DirectionsAnchorMenu'; import { MapAnchorMenu } from './nodes/MapBox/MapAnchorMenu'; import { TaskCompletionBox } from './nodes/TaskCompletedBox'; import { DashFieldViewMenu } from './nodes/formattedText/DashFieldView'; @@ -70,9 +72,8 @@ import { PresBox } from './nodes/trails'; import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; +import { DocData } from '../../fields/DocSymbols'; const { default: { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore -import { DirectionsAnchorMenu } from './nodes/MapBox/DirectionsAnchorMenu'; -import { CalendarManager } from '../util/CalendarManager'; const _global = (window /* browser */ || global) /* node */ as any; @observer @@ -130,9 +131,19 @@ export class MainView extends ObservableReactComponent<{}> { @computed public get mainFreeform(): Opt { return (docs => (docs?.length > 1 ? docs[1] : undefined))(DocListCast(this.mainContainer!.data)); } + @observable public headerBarHeight: number = 0; + headerBarHeightFunc = () => this.headerBarHeight; + @action + toggleTopBar = () => { + if (this.headerBarHeight > 0) { + this.headerBarHeight = 0; + } else { + this.headerBarHeight = 60; + } + }; headerBarDocWidth = () => this.mainDocViewWidth(); - headerBarDocHeight = () => (this._hideUI ? 0 : SettingsManager.Instance?.headerBarHeight ?? 0); + headerBarDocHeight = () => (this._hideUI ? 0 : this.headerBarHeight ?? 0); topMenuHeight = () => (this._hideUI ? 0 : 35); topMenuWidth = returnZero; // value is ignored ... leftMenuWidth = () => (this._hideUI ? 0 : Number(LEFT_MENU_WIDTH.replace('px', ''))); @@ -630,9 +641,11 @@ export class MainView extends ObservableReactComponent<{}> { ); } @computed get mainDocView() { + const headerBar = this._hideUI || !this.headerBarDocHeight?.() ? null : this.headerBarDocView; + console.log('Header = ' + this._hideUI + ' ' + this.headerBarDocHeight?.() + ' ' + headerBar); return ( <> - {this._hideUI || !this.headerBarDocHeight?.() ? null : this.headerBarDocView} + {headerBar} { @action selectMenu = (button: Doc) => { - const title = StrCast(Doc.GetProto(button).title); + const title = StrCast(button[DocData].title); const willOpen = !this._leftMenuFlyoutWidth || this._panelContent !== title; this.closeFlyout(); if (willOpen) { @@ -998,7 +1011,7 @@ export class MainView extends ObservableReactComponent<{}> { {this._hideUI ? null : } - {LinkDescriptionPopup.descriptionPopup ? : null} + {DocButtonState.Instance.LinkEditorDocView ? (DocButtonState.Instance.LinkEditorDocView = undefined))} docView={DocButtonState.Instance.LinkEditorDocView} /> : null} {LinkInfo.Instance?.LinkInfo ? : null} @@ -1008,7 +1021,7 @@ export class MainView extends ObservableReactComponent<{}> { default: case 'dashboard': return (<>

- +
{this.mainDashboardArea} ); diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index d0516336c..a4303c3aa 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -118,7 +118,7 @@ export class MarqueeAnnotator extends ObservableReactComponent { if (!e.aborted && e.linkDocument) { - Doc.GetProto(e.linkDocument).link_relationship = 'cropped image'; - Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.Document.title; - Doc.GetProto(e.linkDocument).link_displayLine = false; + const linkDocData = e.linkDocument[DocData]; + linkDocData.link_relationship = 'cropped image'; + linkDocData.title = 'crop: ' + this.props.Document.title; + linkDocData.link_displayLine = false; } }, }); diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 13057ffbf..952c8f0b4 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -37,7 +37,8 @@ import { PropertiesDocContextSelector } from './PropertiesDocContextSelector'; import { PropertiesSection } from './PropertiesSection'; import './PropertiesView.scss'; import { DefaultStyleProvider } from './StyleProvider'; -import { DocumentView, OpenWhere, StyleProviderFunc } from './nodes/DocumentView'; +import { DocumentView, OpenWhere } from './nodes/DocumentView'; +import { StyleProviderFuncType } from './nodes/FieldView'; import { KeyValueBox } from './nodes/KeyValueBox'; import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails'; const _global = (window /* browser */ || global) /* node */ as any; @@ -45,7 +46,7 @@ const _global = (window /* browser */ || global) /* node */ as any; interface PropertiesViewProps { width: number; height: number; - styleProvider?: StyleProviderFunc; + styleProvider?: StyleProviderFuncType; addDocTab: (doc: Doc, where: OpenWhere) => boolean; } diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx index 086f40e96..623201ed1 100644 --- a/src/client/views/ScriptBox.tsx +++ b/src/client/views/ScriptBox.tsx @@ -11,6 +11,7 @@ import { EditableView } from './EditableView'; import { DocumentIconContainer } from './nodes/DocumentIcon'; import { OverlayView } from './OverlayView'; import './ScriptBox.scss'; +import { DocData } from '../../fields/DocSymbols'; export interface ScriptBoxProps { onSave: (text: string, onError: (error: string) => void) => void; @@ -102,7 +103,7 @@ export class ScriptBox extends React.Component { onCancel={overlayDisposer} onSave={(text, onError) => { if (!text) { - Doc.GetProto(doc)[fieldKey] = undefined; + doc[DocData][fieldKey] = undefined; } else { const script = CompileScript(text, { params: { this: Doc.name, ...contextParams }, @@ -125,7 +126,7 @@ export class ScriptBox extends React.Component { div.innerHTML = 'button'; params.length && DragManager.StartButtonDrag([div], text, doc.title + '-instance', {}, params, (button: Doc) => {}, clientX, clientY); - Doc.GetProto(doc)[fieldKey] = new ScriptField(script); + doc[DocData][fieldKey] = new ScriptField(script); overlayDisposer(); } }} diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 0f4a4260c..1e9272e93 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -18,6 +18,7 @@ import { StyleProp } from './StyleProvider'; import { CollectionStackingView } from './collections/CollectionStackingView'; import { FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import { DocData } from '../../fields/DocSymbols'; interface ExtraProps { fieldKey: string; @@ -90,7 +91,7 @@ export class SidebarAnnos extends ObservableReactComponent { const key = data.split(':')[0]; const val = Field.Copy(this.allMetadata.get(key)); - Doc.GetProto(target)[key] = val; + target[DocData][key] = val; return { type: 'dashField', attrs: { fieldKey: key, docId: '', hideKey: false, editable: true }, @@ -98,7 +99,7 @@ export class SidebarAnnos extends ObservableReactComponent , props: Opt, property: string): any { +export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { const remoteDocHeader = 'author;author_date;noMargin'; const isCaption = property.includes(':caption'); const isAnchor = property.includes(':anchor'); const isNonTransparent = property.includes(':nonTransparent'); const isNonTransparentLevel = isNonTransparent ? Number(property.replace(/.*:nonTransparent([0-9]+).*/, '$1')) : 0; // property.includes(':nonTransparent'); - const isContent = property.includes(':content'); const isAnnotated = property.includes(':annotated'); const isInk = () => doc?._layout_isSvg && !props?.LayoutTemplateString; const isOpen = property.includes(':open'); @@ -125,7 +125,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, case StyleProp.FontFamily: return StrCast(doc?.[fieldKey + 'fontFamily'], StrCast(doc?._text_fontFamily, StrCast(Doc.UserDoc().fontFamily))); case StyleProp.FontWeight: return StrCast(doc?.[fieldKey + 'fontWeight'], StrCast(doc?._text_fontWeight, StrCast(Doc.UserDoc().fontWeight))); case StyleProp.FillColor: return StrCast(doc?._fillColor, StrCast(doc?.fillColor, 'transparent')); - case StyleProp.ShowCaption:return doc?._type_collection === CollectionViewType.Carousel ? undefined: StrCast(doc?._layout_showCaption); + case StyleProp.ShowCaption:return props?.hideCaptions || doc?._type_collection === CollectionViewType.Carousel ? undefined: StrCast(doc?._layout_showCaption); case StyleProp.TitleHeight:return (props?.ScreenToLocalTransform().Scale ?? 1) * NumCast(Doc.UserDoc().headerHeight,30); case StyleProp.ShowTitle: return ( @@ -244,7 +244,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, ? `gray ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (props?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent : lockedPosition() ? undefined // if it's a background & has a cluster color, make the shadow spread really big - : StrCast(doc.layout_fieldKey).includes('_inline') // if doc is an inline document in a text box + : fieldKey.includes('_inline') // if doc is an inline document in a text box ? `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0vw 0vw 0.1vw')}` : DocCast(doc.embedContainer)?.type=== DocumentType.RTF // if doc is embedded in a text document (but not an inline) ? `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0.2vw 0.2vw 0.8vw')}` @@ -316,11 +316,11 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, }; const audio = () => { const audioAnnoState = (doc: Doc) => StrCast(doc.audioAnnoState, 'stopped'); - const audioAnnosCount = (doc: Doc) => StrListCast(doc[Doc.LayoutFieldKey(doc) + '_audioAnnotations']).length; + const audioAnnosCount = (doc: Doc) => StrListCast(doc[fieldKey + 'audioAnnotations']).length; if (!doc || props?.renderDepth === -1 || !audioAnnosCount(doc)) return null; const audioIconColors: { [key: string]: string } = { recording: 'red', playing: 'green', stopped: 'blue' }; return ( - {StrListCast(doc[Doc.LayoutFieldKey(doc) + '_audioAnnotations_text']).lastElement()}
}> + {StrListCast(doc[fieldKey + 'audioAnnotations_text']).lastElement()}
}>
DocumentManager.Instance.getFirstDocumentView(doc)?.playAnnotation()}>
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index e5154efcb..ba7120b93 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -11,9 +11,10 @@ import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { Transform } from '../util/Transform'; import { undoBatch } from '../util/UndoManager'; import { CollectionTreeView } from './collections/CollectionTreeView'; -import { DocumentView } from './nodes/DocumentView'; +import { DocumentView, returnEmptyDocViewList } from './nodes/DocumentView'; import { DefaultStyleProvider } from './StyleProvider'; import './TemplateMenu.scss'; +import { DocData } from '../../fields/DocSymbols'; @observer class TemplateToggle extends React.Component<{ template: string; checked: boolean; toggle: (event: React.ChangeEvent, template: string) => void }> { @@ -79,7 +80,7 @@ export class TemplateMenu extends React.Component { }; componentDidMount() { !this._addedKeys && (this._addedKeys = new ObservableSet()); - [...Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].Document))), ...Array.from(Object.keys(this.props.docViews[0].Document))] + [...Array.from(Object.keys(this.props.docViews[0].Document[DocData])), ...Array.from(Object.keys(this.props.docViews[0].Document))] .filter(key => key.startsWith('layout_')) .map(key => runInAction(() => this._addedKeys.add(key.replace('layout_', '')))); } @@ -113,6 +114,7 @@ export class TemplateMenu extends React.Component { {templateMenu} this._props .ScreenToLocalTransform() - .translate(Doc.NativeWidth(this._props.Document), 0) + .translate(Doc.NativeWidth(this.Document), 0) .scale(this._props.NativeDimScaling?.() || 1); get calendarsKey() { @@ -74,7 +74,7 @@ export class CollectionCalendarView extends CollectionSubView() {
{ + focus = (anchor: Doc, options: FocusViewOptions) => { const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]); if (anchor.type !== DocumentType.CONFIG && !docs.includes(anchor)) return; options.didMove = true; @@ -70,7 +71,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { NativeWidth={returnZero} NativeHeight={returnZero} layout_fitWidth={undefined} - onDoubleClick={this.onChildDoubleClick} + onDoubleClickScript={this.onChildDoubleClick} renderDepth={this._props.renderDepth + 1} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 208fc45b5..79f5baabe 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -66,9 +66,9 @@ export class CollectionCarouselView extends CollectionSubView() { NativeWidth={returnZero} NativeHeight={returnZero} layout_fitWidth={undefined} - setContentView={undefined} - onDoubleClick={this.onContentDoubleClick} - onClick={this.onContentClick} + setContentViewBox={undefined} + onDoubleClickScript={this.onContentDoubleClick} + onClickScript={this.onContentClick} isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive} isContentActive={this._props.childContentsActive ?? this._props.isContentActive() === false ? returnFalse : emptyFunction} hideCaptions={!!carouselShowsCaptions} // hide captions if the carousel is configured to show the captions diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 1f867fc44..87973fd81 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import * as GoldenLayout from '../../../client/goldenLayout'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; -import { AclAdmin, AclEdit } from '../../../fields/DocSymbols'; +import { AclAdmin, AclEdit, DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; @@ -277,8 +277,8 @@ export class CollectionDockingView extends CollectionSubView() { } setupGoldenLayout = async () => { if (this._unmounting) return; - //const config = StrCast(this._props.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this._props.Document))); - const config = StrCast(this._props.Document.dockingConfig); + //const config = StrCast(this.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this.Document))); + const config = StrCast(this.Document.dockingConfig); if (config) { const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g); const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) ?? []; @@ -322,7 +322,7 @@ export class CollectionDockingView extends CollectionSubView() { ); new _global.ResizeObserver(this.onResize).observe(this._containerRef.current); this._reactionDisposer = reaction( - () => StrCast(this._props.Document.dockingConfig), + () => StrCast(this.Document.dockingConfig), config => { if (!this._goldenLayout || this._ignoreStateChange !== config) { // bcz: TODO! really need to diff config with ignoreStateChange and modify the current goldenLayout instead of building a new one. @@ -381,7 +381,7 @@ export class CollectionDockingView extends CollectionSubView() { .map(id => DocServer.GetCachedRefField(id)) .filter(f => f) .map(f => f as Doc); - const changesMade = this._props.Document.dockingConfig !== json; + const changesMade = this.Document.dockingConfig !== json; if (changesMade) { if (![AclAdmin, AclEdit].includes(GetEffectiveAcl(this.dataDoc))) { this.layoutDoc.dockingConfig = json; @@ -449,7 +449,7 @@ export class CollectionDockingView extends CollectionSubView() { if (clone) { const cloned = await Doc.MakeClone(doc); Array.from(cloned.map.entries()).map(entry => (json = json.replace(entry[0], entry[1][Id]))); - Doc.GetProto(cloned.clone).dockingConfig = json; + cloned.clone[DocData].dockingConfig = json; return DashboardView.openDashboard(cloned.clone); } const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g); @@ -463,7 +463,7 @@ export class CollectionDockingView extends CollectionSubView() { const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true, undefined, true) : Doc.MakeEmbedding(origtab); const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeEmbedding(origtabdoc)); if (newtabdocs.length) { - Doc.GetProto(newtab).data = new List(newtabdocs); + newtab[DocData].data = new List(newtabdocs); newtabdocs.forEach(ntab => Doc.SetContainer(ntab, newtab)); } json = json.replace(origtab[Id], newtab[Id]); @@ -479,7 +479,7 @@ export class CollectionDockingView extends CollectionSubView() { stateChanged = () => { this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig()); const json = JSON.stringify(this._goldenLayout.toConfig()); - const changesMade = this._props.Document.dockingConfig !== json; + const changesMade = this.Document.dockingConfig !== json; return changesMade; }; @@ -490,7 +490,7 @@ export class CollectionDockingView extends CollectionSubView() { // if you close a tab that is not embedded somewhere else (an embedded Doc can be opened simultaneously in a tab), then add the tab to recently closed if (tab.DashDoc.embedContainer === this.Document) tab.DashDoc.embedContainer = undefined; if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true); - Doc.RemoveDocFromList(Doc.GetProto(tab.DashDoc), 'proto_embeddings', tab.DashDoc); + Doc.RemoveDocFromList(tab.DashDoc[DocData], 'proto_embeddings', tab.DashDoc); } if (CollectionDockingView.Instance) { const dview = CollectionDockingView.Instance.Document; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index a54a5ec81..2dad377e0 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -19,14 +19,17 @@ import { undoBatch } from '../../util/UndoManager'; import { AntimodeMenu } from '../AntimodeMenu'; import { EditableView } from '../EditableView'; import { MainView } from '../MainView'; -import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; import { CollectionLinearView } from './collectionLinear'; import './CollectionMenu.scss'; +import { DocData } from '../../../fields/DocSymbols'; interface CollectionMenuProps { panelHeight: () => number; panelWidth: () => number; + toggleTopBar: () => void; + topBarHeight: () => number; } @observer @@ -65,15 +68,6 @@ export class CollectionMenu extends AntimodeMenu { } }; - @action - toggleTopBar = () => { - if (SettingsManager.Instance.headerBarHeight > 0) { - SettingsManager.Instance.headerBarHeight = 0; - } else { - SettingsManager.Instance.headerBarHeight = 60; - } - }; - @action toggleProperties = () => { if (MainView.Instance.propertiesWidth() > 0) { @@ -95,6 +89,7 @@ export class CollectionMenu extends AntimodeMenu {
{ } render() { - const headerIcon = SettingsManager.Instance.headerBarHeight > 0 ? 'angle-double-up' : 'angle-double-down'; - const headerTitle = SettingsManager.Instance.headerBarHeight > 0 ? 'Close Header Bar' : 'Open Header Bar'; + const headerIcon = this.props.topBarHeight() > 0 ? 'angle-double-up' : 'angle-double-down'; + const headerTitle = this.props.topBarHeight() > 0 ? 'Close Header Bar' : 'Open Header Bar'; const propIcon = SettingsManager.Instance.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left'; const propTitle = SettingsManager.Instance.propertiesWidth > 0 ? 'Close Properties' : 'Open Properties'; @@ -134,8 +129,8 @@ export class CollectionMenu extends AntimodeMenu { toggleType={ToggleType.BUTTON} type={Type.PRIM} color={SettingsManager.userColor} - onClick={this.toggleTopBar} - toggleStatus={SettingsManager.Instance.headerBarHeight > 0} + onClick={this.props.toggleTopBar} + toggleStatus={this.props.topBarHeight() > 0} icon={} tooltip={headerTitle} /> @@ -219,7 +214,7 @@ export class CollectionViewBaseChrome extends React.Component (Doc.GetProto(this.target).data = new List(source))), + immediate: undoBatch((source: Doc[]) => (this.target[DocData].data = new List(source))), initialize: emptyFunction, }; _onClickCommand = { diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 363db8850..e6ce5baab 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, Field, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Copy, Id } from '../../../fields/FieldSymbols'; @@ -18,8 +18,8 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { LightboxView } from '../LightboxView'; -import { DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView'; -import { FieldViewProps } from '../nodes/FieldView'; +import { DocumentView } from '../nodes/DocumentView'; +import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; import './CollectionNoteTakingView.scss'; @@ -51,7 +51,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } @computed get chromeHidden() { - return BoolCast(this.layoutDoc.chromeHidden) || this._props.onBrowseClick?.() ? true : false; + return BoolCast(this.layoutDoc.chromeHidden) || this._props.onBrowseClickScript?.() ? true : false; } // columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns @computed get colHeaderData() { @@ -189,7 +189,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { }; // let's dive in and get the actual document we want to drag/move around - focusDocument = (doc: Doc, options: DocFocusOptions) => { + focusDocument = (doc: Doc, options: FocusViewOptions) => { Doc.BrushDoc(doc); const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { @@ -254,9 +254,9 @@ export class CollectionNoteTakingView extends CollectionSubView() { rootSelected={this.rootSelected} layout_showTitle={this._props.childlayout_showTitle} dragAction={StrCast(this.layoutDoc.childDragAction) as dropActionType} - onClick={this.onChildClickHandler} - onBrowseClick={this._props.onBrowseClick} - onDoubleClick={this.onChildDoubleClickHandler} + onClickScript={this.onChildClickHandler} + onBrowseClickScript={this._props.onBrowseClickScript} + onDoubleClickScript={this.onChildDoubleClickHandler} ScreenToLocalTransform={noteTakingDocTransform} focus={this.focusDocument} childFilters={this.childDocFilters} @@ -410,7 +410,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { if ((e.ctrlKey || fieldProps.Document._createDocOnCR) && ['Enter'].includes(e.key)) { e.stopPropagation?.(); const newDoc = Doc.MakeCopy(fieldProps.Document, true); - Doc.GetProto(newDoc).text = undefined; + newDoc[DocData].text = undefined; FormattedTextBox.SetSelectOnLoad(newDoc); return this.addDocument?.(newDoc); } @@ -442,7 +442,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } return true; } - } else if (de.complete.linkDragData?.dragDocument.embedContainer === this._props.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) { + } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) { const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' }); if (!this._props.addDocument?.(source)) e.preventDefault(); de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 1239a038a..1394e62ba 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -3,6 +3,7 @@ import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; import { Doc, Opt } from '../../../fields/Doc'; +import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; @@ -23,17 +24,17 @@ import { undoBatch, UndoManager } from '../../util/UndoManager'; import { CollectionSubView } from '../collections/CollectionSubView'; import { LightboxView } from '../LightboxView'; import { AudioWaveform } from '../nodes/audio/AudioWaveform'; -import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; +import { DocumentView, OpenWhere } from '../nodes/DocumentView'; +import { FocusFuncType, FocusViewOptions, StyleProviderFuncType } from '../nodes/FieldView'; import { LabelBox } from '../nodes/LabelBox'; import { VideoBox } from '../nodes/VideoBox'; import { ObservableReactComponent } from '../ObservableReactComponent'; import './CollectionStackedTimeline.scss'; -import { FieldViewProps } from '../nodes/FieldView'; export type CollectionStackedTimelineProps = { Play: () => void; Pause: () => void; - playLink: (linkDoc: Doc, options: DocFocusOptions) => void; + playLink: (linkDoc: Doc, options: FocusViewOptions) => void; playFrom: (seekTimeInSeconds: number, endTime?: number) => void; playing: () => boolean; thumbnails?: () => string[]; @@ -162,7 +163,7 @@ export class CollectionStackedTimeline extends CollectionSubView this.childDocList?.some(item => item === doc); - getView = async (doc: Doc, options: DocFocusOptions): Promise> => + getView = async (doc: Doc, options: FocusViewOptions): Promise> => new Promise>(res => { if (doc.hidden) options.didMove = !(doc.hidden = false); const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); @@ -427,8 +428,8 @@ export class CollectionStackedTimeline extends CollectionSubView number; - styleProvider?: StyleProviderFunc; - playLink: (linkDoc: Doc, options: DocFocusOptions) => void; + styleProvider?: StyleProviderFuncType; + playLink: (linkDoc: Doc, options: FocusViewOptions) => void; setTime: (time: number) => void; startTag: string; endTag: string; @@ -701,7 +702,7 @@ interface StackedTimelineAnchorProps { isDocumentActive?: () => boolean | undefined; ScreenToLocalTransform: () => Transform; _timeline: HTMLDivElement | null; - focus: DocFocusFunc; + focus: FocusFuncType; currentTimecode: () => number; isSelected: () => boolean; stackedTimeline: CollectionStackedTimeline; @@ -810,7 +811,7 @@ class StackedTimelineAnchor extends ObservableReactComponent ScriptField), doublescript: undefined | (() => ScriptField), screenXf: () => Transform, width: () => number, height: () => number) { const anchor = observable({ view: undefined as Opt | null }); - const focusFunc = (doc: Doc, options: DocFocusOptions): number | undefined => { + const focusFunc = (doc: Doc, options: FocusViewOptions): number | undefined => { this._props.playLink(mark, options); return undefined; }; @@ -842,8 +843,8 @@ class StackedTimelineAnchor extends ObservableReactComponent { + focusDocument = (doc: Doc, options: FocusViewOptions) => { Doc.BrushDoc(doc); const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); @@ -288,7 +288,7 @@ export class CollectionStackingView extends CollectionSubView this.refList.splice(this.refList.indexOf(ref), 1)} @@ -670,7 +670,7 @@ export class CollectionStackingView extends CollectionSubView this.isContentActive() && e.stopPropagation()}> {this.renderedSections} {!this.showAddAGroup ? null : ( -
+
)} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index d7c42a975..0aa74aaba 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -21,18 +21,17 @@ import { ImageUtils } from '../../util/Import & Export/ImageUtils'; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; import { UndoManager, undoBatch } from '../../util/UndoManager'; -import { ViewBoxBaseComponent, ViewBoxBaseProps } from '../DocComponent'; +import { ViewBoxBaseComponent } from '../DocComponent'; import { LoadingBox } from '../nodes/LoadingBox'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { CollectionView, CollectionViewProps } from './CollectionView'; -import { returnEmptyDocViewList } from '../nodes/DocumentView'; export interface SubCollectionViewProps extends CollectionViewProps { isAnyChildContentActive: () => boolean; } export function CollectionSubView(moreProps?: X) { - class CollectionSubView extends ViewBoxBaseComponent() { + class CollectionSubView extends ViewBoxBaseComponent() { private dropDisposer?: DragManager.DragDropDisposer; private gestureDisposer?: GestureUtils.GestureEventDisposer; protected _mainCont?: HTMLDivElement; @@ -63,20 +62,16 @@ export function CollectionSubView(moreProps?: X) { } get dataDoc() { - return this._props.TemplateDataDocument instanceof Doc && this._props.Document.isTemplateForField - ? Doc.GetProto(this._props.TemplateDataDocument) - : this._props.Document.resolvedDataDoc - ? this._props.Document - : Doc.GetProto(this._props.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template + return this._props.TemplateDataDocument instanceof Doc && this.Document.isTemplateForField ? Doc.GetProto(this._props.TemplateDataDocument) : this.Document.resolvedDataDoc ? this.Document : Doc.GetProto(this.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template } get childContainerViewPath() { - return this.DocumentView?.().docViewPath ?? returnEmptyDocViewList; + return this.DocumentView?.().docViewPath; } // this returns whether either the collection is selected, or the template that it is part of is selected rootSelected = () => this._props.isSelected() || BoolCast(this._props.TemplateDataDocument && this._props.rootSelected?.()); - // The data field for rendering this collection will be on the this._props.Document unless we're rendering a template in which case we try to use props.TemplateDataDocument. + // The data field for rendering this collection will be on the this.Document unless we're rendering a template in which case we try to use props.TemplateDataDocument. // When a document has a TemplateDataDoc but it's not a template, then it contains its own rendering data, but needs to pass the TemplateDataDoc through // to its children which may be templates. // If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey' @@ -97,14 +92,14 @@ export function CollectionSubView(moreProps?: X) { @computed get childDocList() { return Cast(this.dataField, listSpec(Doc)); } - collectionFilters = () => this._focusFilters ?? StrListCast(this._props.Document._childFilters); - collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this._props.Document._childFiltersByRanges, listSpec('string'), []); + collectionFilters = () => this._focusFilters ?? StrListCast(this.Document._childFilters); + collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.Document._childFiltersByRanges, listSpec('string'), []); // child filters apply to the descendants of the documents in this collection childDocFilters = () => [...(this._props.childFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()]; // unrecursive filters apply to the documents in the collection, but no their children. See Utils.noRecursionHack unrecursiveDocFilters = () => [...(this._props.childFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])]; childDocRangeFilters = () => [...(this._props.childFiltersByRanges?.() || []), ...this.collectionRangeDocFilters()]; - searchFilterDocs = () => this._props.searchFilterDocs?.() ?? DocListCast(this._props.Document._searchFilterDocs); + searchFilterDocs = () => this._props.searchFilterDocs?.() ?? DocListCast(this.Document._searchFilterDocs); @computed.struct get childDocs() { TraceMobx(); let rawdocs: (Doc | Promise)[] = []; @@ -127,7 +122,7 @@ export function CollectionSubView(moreProps?: X) { const childDocFilters = this.childDocFilters(); const childFiltersByRanges = this.childDocRangeFilters(); const searchDocs = this.searchFilterDocs(); - if (this._props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) { + if (this.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) { return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one } @@ -136,9 +131,9 @@ export function CollectionSubView(moreProps?: X) { // dragging facets const dragged = this._props.childFilters?.().some(f => f.includes(Utils.noDragDocsFilter)); if (dragged && SnappingManager.CanEmbed && DragManager.docsBeingDragged.includes(d)) return false; - let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this._props.Document).length > 0; + let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this.Document).length > 0; if (notFiltered) { - notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this._props.Document).length > 0; + notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this.Document).length > 0; const fieldKey = Doc.LayoutFieldKey(d); const annos = !Field.toString(Doc.LayoutField(d) as Field).includes(CollectionView.name); const data = d[annos ? fieldKey + '_annotations' : fieldKey]; @@ -171,7 +166,7 @@ export function CollectionSubView(moreProps?: X) { @action protected async setCursorPosition(position: [number, number]) { let ind; - const doc = this._props.Document; + const doc = this.Document; const id = Doc.UserDoc()[Id]; const email = Doc.CurrentUserEmail; const pos = { x: position[0], y: position[1] }; @@ -207,7 +202,7 @@ export function CollectionSubView(moreProps?: X) { const dropAction = this.layoutDoc.dropAction as dropActionType; // if the dropEvent's dragAction is, say 'embed', but we're just dragging within a collection, we may not actually want to make an embedding. // so we check if our collection has a dropAction set on it and if so, we use that instead. - if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this._props.Document && this.childDocs.includes(d))) { + if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.Document && this.childDocs.includes(d))) { de.complete.docDragData.dropAction = dropAction; } e.stopPropagation(); @@ -471,7 +466,7 @@ export function CollectionSubView(moreProps?: X) { } if (generatedDocuments.length) { // Creating a dash document - const isFreeformView = this._props.Document._type_collection === CollectionViewType.Freeform; + const isFreeformView = this.Document._type_collection === CollectionViewType.Freeform; const set = !isFreeformView ? generatedDocuments : generatedDocuments.length > 1 diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 7036ec41c..ee5147428 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -16,7 +16,8 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; -import { DocFocusOptions, DocumentView } from '../nodes/DocumentView'; +import { DocumentView } from '../nodes/DocumentView'; +import { FocusViewOptions } from '../nodes/FieldView'; import { PresBox } from '../nodes/trails'; import { CollectionSubView } from './CollectionSubView'; import './CollectionTimeView.scss'; @@ -38,7 +39,7 @@ export class CollectionTimeView extends CollectionSubView() { } componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); runInAction(() => { this._childClickedScript = ScriptField.MakeScript('openInLightbox(this)', { this: Doc.name }); this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' }); @@ -68,7 +69,7 @@ export class CollectionTimeView extends CollectionSubView() { }; @action - scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: DocFocusOptions) => { + scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: FocusViewOptions) => { // if in preview, then override document's fields with view spec this._focusFilters = StrListCast(anchor.config_docFilters); this._focusRangeFilters = StrListCast(anchor.config_docRangeFilters); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 76b934802..4696d7948 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -447,7 +447,7 @@ export class CollectionTreeView extends CollectionSubView { isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc) isAnnotationOverlayScrollable?: boolean; // whether the annotation overlay can be vertically scrolled (just for tree views, currently) layoutEngine?: () => string; @@ -63,9 +63,8 @@ interface CollectionViewProps_ extends FieldViewProps { RemFromMap?: (treeViewDoc: Doc, index: number[]) => void; hierarchyIndex?: number[]; // hierarchical index of a document up to the rendering root (primarily used for tree views) } -export interface CollectionViewProps extends React.PropsWithChildren {} @observer -export class CollectionView extends ViewBoxAnnotatableComponent() { +export class CollectionView extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); } diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index f00e42360..da15f8dc5 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -29,7 +29,8 @@ import { LightboxView } from '../LightboxView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; import { Colors } from '../global/globalEnums'; -import { DocFocusOptions, DocumentView, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from '../nodes/DocumentView'; +import { DocumentView, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from '../nodes/DocumentView'; +import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; @@ -37,7 +38,6 @@ import { CollectionDockingView } from './CollectionDockingView'; import { CollectionView } from './CollectionView'; import './TabDocView.scss'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; -import { FieldViewProps } from '../nodes/FieldView'; const _global = (window /* browser */ || global) /* node */ as any; interface TabDocViewProps { @@ -118,7 +118,7 @@ export class TabDocView extends ObservableReactComponent { titleEle.onchange = (e: any) => { undoable(() => { titleEle.size = e.currentTarget.value.length + 3; - Doc.GetProto(doc).title = e.currentTarget.value; + doc[DocData].title = e.currentTarget.value; }, 'edit tab title')(); }; @@ -416,7 +416,7 @@ export class TabDocView extends ObservableReactComponent { return tab !== undefined; }; @action - focusFunc = (doc: Doc, options: DocFocusOptions) => { + focusFunc = (doc: Doc, options: FocusViewOptions) => { if (!this.tab.header.parent._activeContentItem || this.tab.header.parent._activeContentItem !== this.tab.contentItem) { this.tab.header.parent.setActiveContentItem(this.tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost) } @@ -452,7 +452,7 @@ export class TabDocView extends ObservableReactComponent { hideTitle={this._props.keyValue} Document={this._document} TemplateDataDocument={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined} - onBrowseClick={DocumentView.exploreMode} + onBrowseClickScript={DocumentView.exploreMode} waitForDoubleClickToClick={this.waitForDoubleClick} isContentActive={this.isContentActive} isDocumentActive={returnFalse} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 9f40edee1..38a2fe978 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -27,8 +27,8 @@ import { UndoManager, undoBatch, undoable } from '../../util/UndoManager'; import { EditableView } from '../EditableView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; -import { DocumentView, DocumentViewInternal, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; -import { FieldViewProps } from '../nodes/FieldView'; +import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView'; +import { FieldViewProps, StyleProviderFuncType } from '../nodes/FieldView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; @@ -62,7 +62,7 @@ export interface TreeViewProps { ScreenToLocalTransform: () => Transform; contextMenuItems?: { script: ScriptField; filter: ScriptField; icon: string; label: string }[]; dontRegisterView?: boolean; - styleProvider?: StyleProviderFunc | undefined; + styleProvider?: StyleProviderFuncType | undefined; treeViewHideHeaderFields: () => boolean; renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle onCheckedClick?: () => ScriptField; @@ -367,8 +367,9 @@ export class TreeView extends ObservableReactComponent { _width: 1000, _height: 10, }); - Doc.GetProto(bullet).title = ComputedField.MakeFunction('this.text?.Text'); - Doc.GetProto(bullet).data = new List([]); + const bulletData = bullet[DocData]; + bulletData.title = ComputedField.MakeFunction('this.text?.Text'); + bulletData.data = new List([]); DocumentManager.Instance.AddViewRenderedCb(bullet, dv => dv.ComponentView?.setFocus?.()); return bullet; @@ -982,8 +983,8 @@ export class TreeView extends ObservableReactComponent { addDocument={undefined} addDocTab={this._props.addDocTab} pinToPres={this.treeView._props.pinToPres} - onClick={this.onChildClick} - onDoubleClick={this.onChildDoubleClick} + onClickScript={this.onChildClick} + onDoubleClickScript={this.onChildDoubleClick} dragAction={this._props.dragAction} moveDocument={this.move} removeDocument={this._props.removeDoc} @@ -1076,7 +1077,7 @@ export class TreeView extends ObservableReactComponent { fitContentsToBox={returnTrue} hideDecorationTitle={this.treeView.outlineMode} hideResizeHandles={this.treeView.outlineMode} - onClick={this.onChildClick} + onClickScript={this.onChildClick} focus={this.refocus} onKey={this.onKeyDown} hideLinkButton={BoolCast(this.treeView.Document.childHideLinkButton)} @@ -1209,7 +1210,7 @@ export class TreeView extends ObservableReactComponent { move: DragManager.MoveFunction, dragAction: dropActionType, addDocTab: (doc: Doc, where: OpenWhere) => boolean, - styleProvider: undefined | StyleProviderFunc, + styleProvider: undefined | StyleProviderFuncType, screenToLocalXf: () => Transform, isContentActive: (outsideReaction?: boolean) => boolean, panelWidth: () => number, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 5204633ea..f0a31a8c6 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -130,7 +130,7 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent { })} // />, { x: 300, y: 300 }); }) @@ -204,8 +204,8 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent number; NativeHeight?: () => number; originTopLeft?: boolean; @@ -65,12 +65,12 @@ export type collectionFreeformViewProps = { noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) engineProps?: any; getScrollHeight?: () => number | undefined; -}; +} @observer export class CollectionFreeFormView extends CollectionSubView>() { public get displayName() { - return 'CollectionFreeFormView(' + this._props.Document.title?.toString() + ')'; + return 'CollectionFreeFormView(' + this.Document.title?.toString() + ')'; } // this makes mobx trace() statements more descriptive constructor(props: any) { @@ -180,12 +180,10 @@ export class CollectionFreeFormView extends CollectionSubView { CollectionFreeFormDocumentView.animFields.forEach(val => { @@ -223,7 +221,7 @@ export class CollectionFreeFormView extends CollectionSubView (this._keyframeEditing = set); getKeyFrameEditing = () => this._keyframeEditing; - onBrowseClickHandler = () => this._props.onBrowseClick?.() || ScriptCast(this.layoutDoc.onBrowseClick); + onBrowseClickHandler = () => this._props.onBrowseClickScript?.() || ScriptCast(this.layoutDoc.onBrowseClick); onChildClickHandler = () => this._props.childClickScript || ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => this._props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); elementFunc = () => this._layoutElements; @@ -288,14 +286,14 @@ export class CollectionFreeFormView extends CollectionSubView= -1e-4 && curTime <= endTime); } - groupFocus = (anchor: Doc, options: DocFocusOptions) => { + groupFocus = (anchor: Doc, options: FocusViewOptions) => { options.docTransform = new Transform(-NumCast(this.layoutDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.layoutDoc[this.panYFieldKey]) + NumCast(anchor.y), 1); const res = this._props.focus(this.Document, options); options.docTransform = undefined; return res; }; - focus = (anchor: Doc, options: DocFocusOptions) => { + focus = (anchor: Doc, options: FocusViewOptions) => { if (this._lightboxDoc) return; if (anchor === this.Document) { if (options.willZoomCentered && options.zoomScale) { @@ -321,7 +319,7 @@ export class CollectionFreeFormView extends CollectionSubView> => + getView = async (doc: Doc, options: FocusViewOptions): Promise> => new Promise>(res => { if (doc.hidden && this._lightboxDoc !== doc) options.didMove = !(doc.hidden = false); const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); @@ -467,7 +465,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout) .reduce((cluster, cd) => { - const grouping = this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster, -1) : NumCast(cd.group, -1); + const grouping = this.Document._freeform_useClusters ? NumCast(cd.layout_cluster, -1) : NumCast(cd.group, -1); if (grouping !== -1) { const layoutDoc = Doc.Layout(cd); const cx = NumCast(cd.x) - this._clusterDistance / 2; @@ -484,9 +482,9 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).filter(cd => (this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster); + const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster); const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.DocumentView?.())!); - const { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 }; + const { left, top } = clusterDocs[0].getBounds || { left: 0, top: 0 }; const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'embed' : undefined); de.moveDocument = this._props.moveDocument; de.offset = this.screenToFreeformContentsXf.transformDirection(ptsParent.clientX - left, ptsParent.clientY - top); @@ -506,7 +504,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).map(c => this.updateCluster(c)); } @@ -514,7 +512,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout); - if (this._props.Document._freeform_useClusters) { + if (this.Document._freeform_useClusters) { const docFirst = docs[0]; docs.map(doc => this._clusterSets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1))); const preferredInd = NumCast(docFirst.layout_cluster); @@ -557,7 +555,7 @@ export class CollectionFreeFormView extends CollectionSubView { const childLayouts = this.childLayoutPairs.map(pair => pair.layout); - if (this._props.Document._freeform_useClusters) { + if (this.Document._freeform_useClusters) { this._clusterSets.forEach(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)); const preferredInd = NumCast(doc.layout_cluster); doc.layout_cluster = -1; @@ -616,7 +614,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (this._hitCluster !== -1) { !addToSel && SelectionManager.DeselectAll(); - const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster); + const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster); this.selectDocuments(eles); return true; } @@ -810,7 +808,7 @@ export class CollectionFreeFormView extends CollectionSubView DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())) .filter(inkView => inkView?.ComponentView instanceof InkingStroke) - .map(inkView => ({ inkViewBounds: inkView!.getBounds(), inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! })) + .map(inkView => ({ inkViewBounds: inkView!.getBounds, inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! })) .filter( ({ inkViewBounds }) => inkViewBounds && // bounding box of eraser segment and ink stroke overlap @@ -959,8 +957,8 @@ export class CollectionFreeFormView extends CollectionSubView= 0.05 || localTransform.Scale > this.zoomScaling()) { const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20); - this._props.Document[this.scaleFieldKey] = Math.abs(safeScale); - this.setPan(-localTransform.TranslateX / safeScale, (this._props.originTopLeft ? undefined : NumCast(this._props.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale); + this.Document[this.scaleFieldKey] = Math.abs(safeScale); + this.setPan(-localTransform.TranslateX / safeScale, (this._props.originTopLeft ? undefined : NumCast(this.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale); } }; @@ -968,7 +966,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.Document.isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom PresBox.Instance?.pauseAutoPres(); - if (this.layoutDoc._Transform || this._props.Document.treeView_OutlineMode === TreeViewType.outline) return; + if (this.layoutDoc._Transform || this.Document.treeView_OutlineMode === TreeViewType.outline) return; e.stopPropagation(); const docHeight = NumCast(this.Document[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight); const scrollable = this.isAnnotationOverlay && NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this._props.PanelHeight() / this.nativeDimScaling + 1e-4; @@ -989,7 +987,7 @@ export class CollectionFreeFormView extends CollectionSubView { - (this._props.viewDefDivClick || ScriptCast(this._props.Document.onViewDefDivClick))?.script.run({ this: this._props.Document, payload }); + (this._props.viewDefDivClick || ScriptCast(this.Document.onViewDefDivClick))?.script.run({ this: this.Document, payload }); e.stopPropagation(); }; @@ -1377,7 +1375,7 @@ export class CollectionFreeFormView extends CollectionSubView, engine: (poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) => ViewDefResult[] ) { - return engine(poolData, this._props.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps); + return engine(poolData, this.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps); } doFreeformLayout(poolData: Map) { @@ -1437,7 +1435,7 @@ export class CollectionFreeFormView extends CollectionSubView (this.Document._hideInfo || this.Document.annotationOn || this._props.renderDepth ? null : ); componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); super.componentDidMount?.(); setTimeout( action(() => { @@ -1639,15 +1637,15 @@ export class CollectionFreeFormView extends CollectionSubView (this.layoutDoc._autoArrange = !this.layoutDoc._autoArrange), icon: 'compress-arrows-alt', }); - if (this._props.setContentView === emptyFunction) { + if (this._props.setContentViewBox === emptyFunction) { !appearance && ContextMenu.Instance.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'eye' }); return; } @@ -1656,7 +1654,7 @@ export class CollectionFreeFormView extends CollectionSubView this.updateClusters(!this.Document._freeform_useClusters), icon: 'braille' }) : null; @@ -1680,8 +1678,8 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this._props.Document.isGroup && this._props.Document.transcription) { - const text = StrCast(this._props.Document.transcription); + if (this.Document.isGroup && this.Document.transcription) { + const text = StrCast(this.Document.transcription); const lines = text.split('\n'); const height = 30 + 15 * lines.length; @@ -1742,7 +1740,7 @@ export class CollectionFreeFormView extends CollectionSubView - {this._props.Document.annotationOn ? '' : this._props.Document.title?.toString()} + {this.Document.annotationOn ? '' : this.Document.title?.toString()}
); } @@ -1882,10 +1880,10 @@ export class CollectionFreeFormView extends CollectionSubView { - Doc.GetProto(doc).data = new List(selected); - Doc.GetProto(doc).isGroup = makeGroup; - Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform'; + const docData = doc[DocData]; + docData.data = new List(selected); + docData.isGroup = makeGroup; + docData.title = makeGroup ? 'grouping' : 'nested freeform'; doc._freeform_panX = doc._freeform_panY = 0; return doc; })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 113ffedb3..f25872c2b 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -192,7 +192,7 @@ export class CollectionGridView extends CollectionSubView() { {...this._props} NativeWidth={returnZero} NativeHeight={returnZero} - setContentView={emptyFunction} + setContentViewBox={emptyFunction} Document={layout} TemplateDataDocument={layout.resolvedDataDoc as Doc} isContentActive={this.isChildContentActive} @@ -200,7 +200,7 @@ export class CollectionGridView extends CollectionSubView() { PanelHeight={height} ScreenToLocalTransform={dxf} whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} - onClick={this.onChildClickHandler} + onClickScript={this.onChildClickHandler} renderDepth={this._props.renderDepth + 1} dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy' /> @@ -340,7 +340,7 @@ export class CollectionGridView extends CollectionSubView() { * Handles text document creation on double click. */ onPointerDown = (e: React.PointerEvent) => { - if (this._props.isContentActive(true)) { + if (this._props.isContentActive()) { setupMoveUpEvents( this, e, diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 40b4151fe..1fa106b45 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -267,8 +267,8 @@ export class CollectionMulticolumnView extends CollectionSubView() { PanelHeight={height} rootSelected={this.rootSelected} dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType} - onClick={this.onChildClickHandler} - onDoubleClick={this.onChildDoubleClickHandler} + onClickScript={this.onChildClickHandler} + onDoubleClickScript={this.onChildDoubleClickHandler} suppressSetHeight={true} ScreenToLocalTransform={dxf} isContentActive={this.isChildContentActive} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 04a4042f1..97a444b8c 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -262,8 +262,8 @@ export class CollectionMultirowView extends CollectionSubView() { PanelHeight={height} rootSelected={this.rootSelected} dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType} - onClick={this.onChildClickHandler} - onDoubleClick={this.onChildDoubleClickHandler} + onClickScript={this.onChildClickHandler} + onDoubleClickScript={this.onChildDoubleClickHandler} ScreenToLocalTransform={dxf} isContentActive={this.isChildContentActive} isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive} diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx index c38c6dc4e..d580d9c52 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -1,16 +1,16 @@ -import { action, observable } from 'mobx'; +import { action } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; import { UndoManager } from '../../../util/UndoManager'; import { StyleProp } from '../../StyleProvider'; -import { StyleProviderFunc } from '../../nodes/DocumentView'; +import { StyleProviderFuncType } from '../../nodes/FieldView'; import { DimUnit } from './CollectionMulticolumnView'; interface ResizerProps { width: number; - styleProvider?: StyleProviderFunc; + styleProvider?: StyleProviderFuncType; isContentActive?: () => boolean | undefined; columnUnitLength(): number | undefined; toLeft?: Doc; diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx index 6f1b3b425..73d08d5ef 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx @@ -1,16 +1,16 @@ -import { action, observable } from 'mobx'; +import { action } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; import { UndoManager } from '../../../util/UndoManager'; import { StyleProp } from '../../StyleProvider'; -import { StyleProviderFunc } from '../../nodes/DocumentView'; +import { StyleProviderFuncType } from '../../nodes/FieldView'; import { DimUnit } from './CollectionMultirowView'; interface ResizerProps { height: number; - styleProvider?: StyleProviderFunc; + styleProvider?: StyleProviderFuncType; isContentActive?: () => boolean | undefined; columnUnitLength(): number | undefined; toTop?: Doc; diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 227274a53..ec91b25f8 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -16,7 +16,8 @@ import { undoable, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; -import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView'; +import { DocumentView } from '../../nodes/DocumentView'; +import { FocusViewOptions, FieldViewProps } from '../../nodes/FieldView'; import { KeyValueBox } from '../../nodes/KeyValueBox'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../../StyleProvider'; @@ -24,7 +25,6 @@ import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; -import { FieldViewProps } from '../../nodes/FieldView'; export enum ColumnType { Number, @@ -147,7 +147,7 @@ export class CollectionSchemaView extends CollectionSubView() { } componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); document.addEventListener('keydown', this.onKeyDown); Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1])); @@ -498,13 +498,13 @@ export class CollectionSchemaView extends CollectionSubView() { ContextMenu.Instance.displayMenu(x, y, undefined, true); }; - focusDocument = (doc: Doc, options: DocFocusOptions) => { + focusDocument = (doc: Doc, options: FocusViewOptions) => { Doc.BrushDoc(doc); this.scrollToDoc(doc, options); return undefined; }; - scrollToDoc = (doc: Doc, options: DocFocusOptions) => { + scrollToDoc = (doc: Doc, options: FocusViewOptions) => { const found = this._tableContentRef && Array.from(this._tableContentRef.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { const rect = found.getBoundingClientRect(); diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 3f94e7fc1..f2fe0dde7 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -12,7 +12,7 @@ import { DragManager } from '../../../util/DragManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { undoable } from '../../../util/UndoManager'; -import { ViewBoxBaseComponent, ViewBoxBaseProps } from '../../DocComponent'; +import { ViewBoxBaseComponent } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; import { OpenWhere } from '../../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../../nodes/FieldView'; @@ -20,17 +20,17 @@ import { CollectionSchemaView } from './CollectionSchemaView'; import './CollectionSchemaView.scss'; import { SchemaTableCell } from './SchemaTableCell'; -interface SchemaRowBoxProps { +interface SchemaRowBoxProps extends FieldViewProps { rowIndex: number; } @observer -export class SchemaRowBox extends ViewBoxBaseComponent() { +export class SchemaRowBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string, rowIndex: number) { return FieldView.LayoutString(SchemaRowBox, fieldKey).replace('fieldKey', `rowIndex={${rowIndex}} fieldKey`); } private _ref: HTMLDivElement | null = null; - constructor(props: any) { + constructor(props: SchemaRowBoxProps) { super(props); makeObservable(this); } @@ -50,7 +50,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent { diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 422c4155d..fda5764dd 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -18,7 +18,7 @@ import { EditableView } from '../../EditableView'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider } from '../../StyleProvider'; import { Colors } from '../../global/globalEnums'; -import { OpenWhere } from '../../nodes/DocumentView'; +import { OpenWhere, returnEmptyDocViewList } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { KeyValueBox } from '../../nodes/KeyValueBox'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; @@ -49,7 +49,7 @@ export interface SchemaTableCellProps { @observer export class SchemaTableCell extends ObservableReactComponent { - constructor(props: any) { + constructor(props: SchemaTableCellProps) { super(props); makeObservable(this); } @@ -75,6 +75,7 @@ export class SchemaTableCell extends ObservableReactComponent { render() { const sourceDoc = this.props.docView.Document; const sourceAnchor = this.props.docView.anchorViewDoc ?? sourceDoc; - const style = this.props.style ?? (dv => ({ left: dv?.left || 0, top: this.props.docView.topMost ? undefined : (dv?.bottom || 0) + 15, bottom: this.props.docView.topMost ? 20 : undefined, maxWidth: 200 }))(this.props.docView.getBounds()); + const style = this.props.style ?? (dv => ({ left: dv?.left || 0, top: this.props.docView.topMost ? undefined : (dv?.bottom || 0) + 15, bottom: this.props.docView.topMost ? 20 : undefined, maxWidth: 200 }))(this.props.docView.getBounds); return (
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index 91142b90b..028d3da53 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -47,18 +47,18 @@ export class LinkMenuGroup extends React.Component { const sourceDoc = this.props.docView.anchorViewDoc ?? (this.props.docView.Document.type === DocumentType.LINK // - ? this.props.docView.props.LayoutTemplateString?.includes('link_anchor_1') + ? this.props.docView._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(linkDoc.link_anchor_1) : DocCast(linkDoc.link_anchor_2) : this.props.sourceDoc); const destDoc = !sourceDoc ? undefined : this.props.docView.Document.type === DocumentType.LINK - ? this.props.docView.props.LayoutTemplateString?.includes('link_anchor_1') - ? DocCast(linkDoc.link_anchor_2) - : DocCast(linkDoc.link_anchor_1) - : LinkManager.getOppositeAnchor(linkDoc, sourceDoc) || - LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.link_anchor_2, Doc, null).annotationOn === sourceDoc ? Cast(linkDoc.link_anchor_2, Doc, null) : Cast(linkDoc.link_anchor_1, Doc, null)); + ? this.props.docView._props.LayoutTemplateString?.includes('link_anchor_1') + ? DocCast(linkDoc.link_anchor_2) + : DocCast(linkDoc.link_anchor_1) + : LinkManager.getOppositeAnchor(linkDoc, sourceDoc) || + LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.link_anchor_2, Doc, null).annotationOn === sourceDoc ? Cast(linkDoc.link_anchor_2, Doc, null) : Cast(linkDoc.link_anchor_1, Doc, null)); return !destDoc || !sourceDoc ? null : ( { addDocTab={this.addDocTab} pinToPres={TabDocView.PinDoc} bringToFront={emptyFunction} - onBrowseClick={DocumentView.exploreMode} + onBrowseClickScript={DocumentView.exploreMode} focus={emptyFunction} /> diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 1729af191..2b71fd156 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -5,6 +5,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { DateField } from '../../../fields/DateField'; import { Doc } from '../../../fields/Doc'; +import { DocData } from '../../../fields/DocSymbols'; import { ComputedField } from '../../../fields/ScriptField'; import { Cast, DateCast, NumCast } from '../../../fields/Types'; import { AudioField, nullAudio } from '../../../fields/URLField'; @@ -19,8 +20,7 @@ import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import './AudioBox.scss'; -import { DocFocusOptions } from './DocumentView'; -import { FieldView, FieldViewProps } from './FieldView'; +import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; /** @@ -121,7 +121,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { @action componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); if (this.path) { this.mediaState = media_state.Paused; this.setPlayheadTime(NumCast(this.layoutDoc.clipStart)); @@ -374,9 +374,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { action(() => { const newDoc = DocUtils.GetNewTextDoc('', NumCast(this.Document.x), NumCast(this.Document.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height)); const textField = Doc.LayoutFieldKey(newDoc); - Doc.GetProto(newDoc)[`${textField}_recordingSource`] = this.dataDoc; - Doc.GetProto(newDoc)[`${textField}_recordingStart`] = ComputedField.MakeFunction(`this.${textField}_recordingSource.${this.fieldKey}_recordingStart`); - Doc.GetProto(newDoc).mediaState = ComputedField.MakeFunction(`this.${textField}_recordingSource.mediaState`); + const newDocData = newDoc[DocData]; + newDocData[`${textField}_recordingSource`] = this.dataDoc; + newDocData[`${textField}_recordingStart`] = ComputedField.MakeFunction(`this.${textField}_recordingSource.${this.fieldKey}_recordingStart`); + newDocData.mediaState = ComputedField.MakeFunction(`this.${textField}_recordingSource.mediaState`); if (Doc.IsInMyOverlay(this.Document)) { newDoc.overlayX = this.Document.x; newDoc.overlayY = NumCast(this.Document.y) + NumCast(this.layoutDoc._height); @@ -432,7 +433,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { }; // plays link - playLink = (link: Doc, options: DocFocusOptions) => { + playLink = (link: Doc, options: FocusViewOptions) => { if (link.annotationOn === this.Document) { if (!this.layoutDoc.dontAutoPlayFollowedLinks) { this.playFrom(this.timeline?.anchorStart(link) || 0, this.timeline?.anchorEnd(link)); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 73709c17e..0ae4ed62c 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -38,8 +38,8 @@ export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentView CollectionFreeFormView: CollectionFreeFormView; } @observer -export class CollectionFreeFormDocumentViewWrapper extends ObservableReactComponent implements CollectionFreeFormDocumentViewProps { - constructor(props: any) { +export class CollectionFreeFormDocumentViewWrapper extends ObservableReactComponent { + constructor(props: CollectionFreeFormDocumentViewWrapperProps) { super(props); makeObservable(this); } @@ -104,7 +104,7 @@ export class CollectionFreeFormDocumentViewWrapper extends ObservableReactCompon ); } } -export interface CollectionFreeFormDocumentViewProps { +export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { w_X: () => number; w_Y: () => number; w_Z: () => number; @@ -125,8 +125,8 @@ export interface CollectionFreeFormDocumentViewProps { } @observer -export class CollectionFreeFormDocumentView extends DocComponent() { - constructor(props: any) { +export class CollectionFreeFormDocumentView extends DocComponent() { + constructor(props: CollectionFreeFormDocumentViewProps) { super(props); makeObservable(this); } diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 500eb52ac..116dc48a6 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -8,20 +8,20 @@ import { DocCast, NumCast, StrCast } from '../../../fields/Types'; import { DocUtils, Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './ComparisonBox.scss'; -import { DocumentView, returnEmptyDocViewList } from './DocumentView'; +import { DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; @observer -export class ComparisonBox extends ViewBoxAnnotatableComponent() { +export class ComparisonBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ComparisonBox, fieldKey); } private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined]; - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); } @@ -35,7 +35,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { this._disposers[disposerId]?.(); @@ -152,9 +152,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_1'), true); moveDoc2 = (doc: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_2'), true); remDoc1 = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc) => res && this.remDoc(doc, this.fieldKey + '_1'), true); @@ -181,7 +178,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() { +export class DataVizBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { private _mainCont: React.RefObject = React.createRef(); private _marqueeref = React.createRef(); private _annotationLayer: React.RefObject = React.createRef(); @@ -46,10 +46,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent(); - constructor(props: ViewBoxAnnotatableProps & FieldViewProps) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); } @computed get annotationLayer() { @@ -233,7 +233,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar') ); }; - getView = async (doc: Doc, options: DocFocusOptions) => { + getView = async (doc: Doc, options: FocusViewOptions) => { if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { options.didMove = true; this.toggleSidebar(); @@ -254,7 +254,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent this.removeDocument(doc, sidebarKey); componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData(); } diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 55859b92b..9538cebb2 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -24,7 +24,6 @@ import { YoutubeBox } from './../../apis/youtube/YoutubeBox'; import { AudioBox } from './AudioBox'; import { ComparisonBox } from './ComparisonBox'; import { DataVizBox } from './DataVizBox/DataVizBox'; -import { DocumentViewProps } from './DocumentView'; import './DocumentView.scss'; import { EquationBox } from './EquationBox'; import { FieldView, FieldViewProps } from './FieldView'; @@ -114,13 +113,11 @@ export class HTMLtag extends React.Component { } } +export interface DocumentContentsViewProps extends FieldViewProps { + layoutFieldKey: string; +} @observer -export class DocumentContentsView extends ObservableReactComponent< - FieldViewProps & { - onClick?: () => ScriptField; - LayoutTemplate?: () => Opt; - } -> { +export class DocumentContentsView extends ObservableReactComponent { constructor(props: any) { super(props); makeObservable(this); @@ -130,8 +127,8 @@ export class DocumentContentsView extends ObservableReactComponent< TraceMobx(); if (this._props.LayoutTemplateString) return this._props.LayoutTemplateString; if (!this.layoutDoc) return '

awaiting layout

'; - if (this._props.fieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString()); - const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.fieldKey ? this._props.fieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string'); + if (this._props.layoutFieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString()); + const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.layoutFieldKey ? this._props.layoutFieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string'); if (layout === undefined) return this._props.Document.data ? "" : KeyValueBox.LayoutString(); if (typeof layout === 'string') return layout; return '

Loading layout

'; @@ -143,26 +140,26 @@ export class DocumentContentsView extends ObservableReactComponent< const template: Doc = this._props.LayoutTemplate?.() || (this._props.LayoutTemplateString && this._props.Document) || - (this._props.fieldKey && StrCast(this._props.Document[this._props.fieldKey]) && this._props.Document) || - Doc.Layout(this._props.Document, this._props.fieldKey ? Cast(this._props.Document[this._props.fieldKey], Doc, null) : undefined); + (this._props.layoutFieldKey && StrCast(this._props.Document[this._props.layoutFieldKey]) && this._props.Document) || + Doc.Layout(this._props.Document, this._props.layoutFieldKey ? Cast(this._props.Document[this._props.layoutFieldKey], Doc, null) : undefined); return Doc.expandTemplateLayout(template, this._props.Document); } CreateBindings(onClick: Opt, onInput: Opt): JsxBindings { const docOnlyProps = [ - // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews + // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews 'hideResizeHandles', 'hideTitle', 'contentPointerEvents', - 'radialMenu', 'LayoutTemplateString', 'LayoutTemplate', + 'layoutFieldKey', 'dontCenter', 'contextMenuItems', //'onClick', // don't need to omit this since it will be set - 'onDoubleClick', - 'onPointerDown', - 'onPointerUp', + 'onDoubleClickScript', + 'onPointerDownScript', + 'onPointerUpScript', ]; const templateDataDoc = this._props.TemplateDataDocument ?? (this.layoutDoc !== this._props.Document ? this._props.Document[DocData] : undefined); const list: BindingProps & React.DetailedHTMLProps, HTMLDivElement> = { diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx index 5ce08cdc3..4a22766cc 100644 --- a/src/client/views/nodes/DocumentIcon.tsx +++ b/src/client/views/nodes/DocumentIcon.tsx @@ -29,7 +29,7 @@ export class DocumentIcon extends ObservableReactComponent { } render() { const view = this._props.view; - const { left, top, right, bottom } = view.getBounds() || { left: 0, top: 0, right: 0, bottom: 0 }; + const { left, top, right, bottom } = view.getBounds || { left: 0, top: 0, right: 0, bottom: 0 }; return (
rect.width) { - LinkDescriptionPopup.popupX -= 190; + if (LinkDescriptionPopup.Instance.popupX + 200 > rect.width) { + LinkDescriptionPopup.Instance.popupX -= 190; TaskCompletionBox.popupX -= 40; } - if (LinkDescriptionPopup.popupY + 100 > rect.height) { - LinkDescriptionPopup.popupY -= 40; + if (LinkDescriptionPopup.Instance.popupY + 100 > rect.height) { + LinkDescriptionPopup.Instance.popupY -= 40; TaskCompletionBox.popupY -= 40; } setTimeout( - action(() => { - TaskCompletionBox.taskCompleted = false; - }), + action(() => (TaskCompletionBox.taskCompleted = false)), 2500 ); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 444c300f3..3e5e43b47 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -3,19 +3,17 @@ import { Dropdown, DropdownType, Type } from 'browndash-components'; import { Howl } from 'howler'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { computedFn } from 'mobx-utils'; import * as React from 'react'; import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal'; import { Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; -import { AclPrivate, Animation, AudioPlay, DocViews } from '../../../fields/DocSymbols'; +import { AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; -import { RefField } from '../../../fields/RefField'; import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; -import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { AudioField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; import { DocServer } from '../../DocServer'; @@ -33,34 +31,27 @@ import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; import { SharingManager } from '../../util/SharingManager'; import { SnappingManager } from '../../util/SnappingManager'; -import { Transform } from '../../util/Transform'; -import { UndoManager, undoBatch } from '../../util/UndoManager'; +import { UndoManager, undoBatch, undoable } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { DocComponent } from '../DocComponent'; +import { DocComponent, ViewBoxInterface } from '../DocComponent'; import { EditableView } from '../EditableView'; import { GestureOverlay } from '../GestureOverlay'; import { LightboxView } from '../LightboxView'; -import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; -import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; import { DocumentContentsView, ObserverJsxParser } from './DocumentContentsView'; import { DocumentLinksButton } from './DocumentLinksButton'; import './DocumentView.scss'; -import { FieldViewProps } from './FieldView'; +import { FieldViewProps, FieldViewSharedProps } from './FieldView'; import { KeyValueBox } from './KeyValueBox'; import { LinkAnchorBox } from './LinkAnchorBox'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { PresEffect, PresEffectDirection } from './trails'; -import { PinProps, PresBox } from './trails/PresBox'; - interface Window { MediaRecorder: MediaRecorder; } - declare class MediaRecorder { - // whatever MediaRecorder has - constructor(e: any); + constructor(e: any); // whatever MediaRecorder has } export enum OpenWhereMod { @@ -92,114 +83,7 @@ export enum OpenWhere { export function returnEmptyDocViewList() { return [] as DocumentView[]; } -export interface DocFocusOptions { - willPan?: boolean; // determines whether to pan to target document - willZoomCentered?: boolean; // determines whether to zoom in on target document. if zoomScale is 0, this just centers the document - zoomScale?: number; // percent of containing frame to zoom into document - zoomTime?: number; - didMove?: boolean; // whether a document was changed during the showDocument process - docTransform?: Transform; // when a document can't be panned and zoomed within its own container (say a group), then we need to continue to move up the render hierarchy to find something that can pan and zoom. when this happens the docTransform must accumulate all the transforms of each level of the hierarchy - instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom) - preview?: boolean; // whether changes should be previewed by the componentView or written to the document - effect?: Doc; // animation effect for focus - noSelect?: boolean; // whether target should be selected after focusing - playAudio?: boolean; // whether to play audio annotation on focus - playMedia?: boolean; // whether to play start target videos - openLocation?: OpenWhere; // where to open a missing document - zoomTextSelections?: boolean; // whether to display a zoomed overlay of anchor text selections - toggleTarget?: boolean; // whether to toggle target on and off - anchorDoc?: Doc; // doc containing anchor info to apply at end of focus to target doc - easeFunc?: 'linear' | 'ease'; // transition method for scrolling -} -export type DocFocusFunc = (doc: Doc, options: DocFocusOptions) => Opt; -export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; -export interface DocComponentView { - fieldKey?: string; - annotationKey?: string; - updateIcon?: () => void; // updates the icon representation of the document - getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) - restoreView?: (viewSpec: Doc) => boolean; - scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: DocFocusOptions) => Opt; // returns the duration of the focus - brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number, holdTime: number) => void; // highlight a region of a view (used by freeforms) - getView?: (doc: Doc, options: DocFocusOptions) => Promise>; // returns a nested DocumentView for the specified doc or undefined - addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox - addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections) - select?: (ctrlKey: boolean, shiftKey: boolean) => void; - focus?: (textAnchor: Doc, options: DocFocusOptions) => Opt; - isAnyChildContentActive?: () => boolean; // is any child content of the document active - onClickScriptDisable?: () => 'never' | 'always'; // disable click scripts : never, always, or undefined = only when selected - getKeyFrameEditing?: () => boolean; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown) - setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown) - playFrom?: (time: number, endTime?: number) => void; - Pause?: () => void; // pause a media document (eg, audio/video) - IsPlaying?: () => boolean; // is a media document playing - TogglePause?: (keep?: boolean) => void; // toggle media document playing state - setFocus?: () => void; // sets input focus to the componentView - setData?: (data: Field | Promise) => boolean; - componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null; - dragStarting?: (snapToDraggedDoc: boolean, showGroupDragTarget: boolean, visited: Set) => void; - incrementalRendering?: () => void; - infoUI?: () => JSX.Element | null; - screenBounds?: () => Opt<{ left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } }>; - ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; - ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; - snapPt?: (pt: { X: number; Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number; Y: number }; distance: number }; - search?: (str: string, bwd?: boolean, clear?: boolean) => boolean; -} -/** - * props that DocumentViews, DocumentInternalViews and FieldViews all can use - * */ -export interface DocumentViewSharedProps { - Document: Doc; - LayoutTemplateString?: string; - TemplateDataDocument?: Doc; - renderDepth: number; - scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document - treeViewDoc?: Doc; - xPadding?: number; - yPadding?: number; - dontRegisterView?: boolean; - dropAction?: dropActionType; - dragAction?: dropActionType; - forceAutoHeight?: boolean; - ignoreAutoHeight?: boolean; - disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. - CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView; - containerViewPath?: () => DocumentView[]; - fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document - isGroupActive?: () => string | undefined; // is this document part of a group that is active - setContentView?: (view: DocComponentView) => any; - PanelWidth: () => number; - PanelHeight: () => number; - isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events - isContentActive: () => boolean | undefined; // whether document contents should handle pointer events - childFilters: () => string[]; - childFiltersByRanges: () => string[]; - styleProvider: Opt; - setTitleFocus?: () => void; - focus: DocFocusFunc; - layout_fitWidth?: (doc: Doc) => boolean | undefined; - searchFilterDocs: () => Doc[]; - layout_showTitle?: () => string; - whenChildContentsActiveChanged: (isActive: boolean) => void; - rootSelected?: () => boolean; // whether the root of a template has been selected - addDocTab: (doc: Doc, where: OpenWhere) => boolean; - filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) - addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; - removeDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; - moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => boolean; - pinToPres: (document: Doc, pinProps: PinProps) => void; - ScreenToLocalTransform: () => Transform; - bringToFront: (doc: Doc, sendToBack?: boolean) => void; - waitForDoubleClickToClick?: () => 'never' | 'always' | undefined; - defaultDoubleClick?: () => 'default' | 'ignore' | undefined; - pointerEvents?: () => Opt; -} - -/** - * props that are used by DocumentViews and DocumentInternalViews but not by the contents of those views (FieldViews). - */ -export interface DocumentViewProps extends DocumentViewSharedProps { +export interface DocumentViewProps extends FieldViewSharedProps { hideDecorations?: boolean; // whether to suppress all DocumentDecorations when doc is selected hideResizeHandles?: boolean; // whether to suppress resized handles on doc decorations when this document is selected hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings @@ -221,35 +105,22 @@ export interface DocumentViewProps extends DocumentViewSharedProps { onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected NativeWidth?: () => number; NativeHeight?: () => number; - LayoutTemplate?: () => Opt; contextMenuItems?: () => { script: ScriptField; filter?: ScriptField; label: string; icon: string }[]; - onClick?: () => ScriptField; - onDoubleClick?: () => ScriptField; - onPointerDown?: () => ScriptField; - onPointerUp?: () => ScriptField; - onBrowseClick?: () => ScriptField | undefined; - onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined; dragStarting?: () => void; dragEnding?: () => void; } - -/** - * props used by DocInternalViews and FieldViews but not DocumentViews - * these props correspond to things that the DocumentView creates and thus doesn't need to receive as a prop - */ -export interface DocumentViewInternalSharedProps { - select: (ctrlPressed: boolean, shiftPress?: boolean) => void; - isSelected: () => boolean; - docViewPath: () => DocumentView[]; - NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal -} -export interface DocumentViewInternalProps extends DocumentViewProps, DocumentViewInternalSharedProps { - docViewPublic: () => DocumentView; -} - @observer -export class DocumentViewInternal extends DocComponent() { +export class DocumentViewInternal extends DocComponent() { + // this makes mobx trace() statements more descriptive + public get displayName() { return 'DocumentViewInternal(' + this.Document.title + ')'; } // prettier-ignore public static SelectAfterContextMenu = true; // whether a document should be selected after it's contextmenu is triggered. + + /** + * This function is filled in by MainView to allow non-viewBox views to add Docs as tabs without + * needing to know about/reference MainView + */ + public static addDocTabFunc: (doc: Doc, location: OpenWhere) => boolean = returnFalse; + private _disposers: { [name: string]: IReactionDisposer } = {}; private _doubleClickTimeout: NodeJS.Timeout | undefined; private _singleClickFunc: undefined | (() => any); @@ -262,79 +133,51 @@ export class DocumentViewInternal extends DocComponent(); private _titleRef = React.createRef(); private _dropDisposer?: DragManager.DragDropDisposer; - constructor(props: any) { + constructor(props: FieldViewProps & DocumentViewProps) { super(props); makeObservable(this); } - @observable _componentView: Opt = undefined; // needs to be accessed from DocumentView wrapper class + @observable _changingTitleField = false; + @observable _titleDropDownInnerWidth = 0; // width of menu dropdown when setting doc title + @observable _mounted = false; // turn off all pointer events if component isn't yet mounted (enables nested Docs in alternate UI textboxes that appear on hover which otherwise would grab focus from the text box, reverting to the original UI ) + @observable _isContentActive: boolean | undefined = undefined; + @observable _pointerEvents: 'none' | 'all' | 'visiblePainted' | undefined = undefined; + @observable _componentView: Opt = undefined; // needs to be accessed from DocumentView wrapper class @observable _animateScaleTime: Opt = undefined; // milliseconds for animating between views. defaults to 300 if not uset @observable _animateScalingTo = 0; - public get animateScaleTime() { - return this._animateScaleTime ?? 100; - } - public get displayName() { - return 'DocumentViewInternal(' + this.Document.title + ')'; - } // this makes mobx trace() statements more descriptive - - public get DocumentView() { - return this._props.docViewPublic; - } + get _contentDiv() { return this._mainCont.current; } // prettier-ignore + get _docView() { return this._props.DocumentView?.(); } // prettier-ignore + + animateScaleTime = () => this._animateScaleTime ?? 100; + style = (doc: Doc, sprop: StyleProp | string) => this._props.styleProvider?.(doc, this._props, sprop); + @computed get layout_showTitle() { return this.style(this.layoutDoc, StyleProp.ShowTitle) as Opt; } // prettier-ignore + @computed get opacity() { return this.style(this.layoutDoc, StyleProp.Opacity); } // prettier-ignore + @computed get boxShadow() { return this.style(this.layoutDoc, StyleProp.BoxShadow); } // prettier-ignore + @computed get borderRounding() { return this.style(this.layoutDoc, StyleProp.BorderRounding); } // prettier-ignore + @computed get widgetDecorations() { return this.style(this.layoutDoc, StyleProp.Decorations); } // prettier-ignore + @computed get backgroundBoxColor() { return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':box'); } // prettier-ignore + @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) ?? 0; } // prettier-ignore + @computed get layout_showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) ?? 0; } // prettier-ignore + @computed get titleHeight() { return this.style(this.layoutDoc, StyleProp.TitleHeight) ?? 0; } // prettier-ignore + @computed get docContents() { return this.style(this.Document, StyleProp.DocContents); } // prettier-ignore + @computed get highlighting() { return this.style(this.Document, StyleProp.Highlighting); } // prettier-ignore + @computed get borderPath() { return this.style(this.Document, StyleProp.BorderPath); } // prettier-ignore - public get ContentDiv() { - return this._mainCont.current; - } - public get LayoutFieldKey() { - return Doc.LayoutFieldKey(this.layoutDoc); - } - @computed get styleProps(): FieldViewProps { - return { ...this._props, fieldKey: '' }; - } - @computed get layout_showTitle() { - return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.ShowTitle) as Opt; - } - @computed get NativeDimScaling() { - return this._props.NativeDimScaling?.() || 1; - } - @computed get thumb() { - return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url?.href.replace('.png', '_m.png'); - } - @computed get opacity() { - return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.Opacity); - } - @computed get boxShadow() { - return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.BoxShadow); - } - @computed get borderRounding() { - return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.BorderRounding); - } - @computed get widgetDecorations() { - TraceMobx(); - return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.Decorations); - } - @computed get backgroundBoxColor() { - return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.BackgroundColor + ':box'); - } - @computed get docContents() { - return this._props.styleProvider?.(this.Document, this.styleProps, StyleProp.DocContents); - } - @computed get headerMargin() { - return this._props?.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.HeaderMargin) || 0; - } - @computed get layout_showCaption() { - return this._props?.hideCaptions ? undefined : this._props?.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.ShowCaption) || 0; + @computed get onClickHandler() { + return this._props.onClickScript?.() ?? this._props.onBrowseClickScript?.() ?? ScriptCast(this.Document.onClick, ScriptCast(this.layoutDoc.onClick)); } - @computed get titleHeight() { - return this._props?.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.TitleHeight) || 0; + @computed get onDoubleClickHandler() { + return this._props.onDoubleClickScript?.() ?? ScriptCast(this.layoutDoc.onDoubleClick, ScriptCast(this.Document.onDoubleClick)); } - @observable _pointerEvents: 'none' | 'all' | 'visiblePainted' | undefined = undefined; - @computed get pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined { - return this._pointerEvents; + @computed get onPointerDownHandler() { + return this._props.onPointerDownScript?.() ?? ScriptCast(this.layoutDoc.onPointerDown, ScriptCast(this.Document.onPointerDown)); } - @computed get finalLayoutKey() { - return StrCast(this.Document.layout_fieldKey, 'layout'); + @computed get onPointerUpHandler() { + return this._props.onPointerUpScript?.() ?? ScriptCast(this.layoutDoc.onPointerUp, ScriptCast(this.Document.onPointerUp)); } + @computed get disableClickScriptFunc() { const onScriptDisable = this._props.onClickScriptDisable ?? this._componentView?.onClickScriptDisable?.() ?? this.layoutDoc.onClickScriptDisable; // prettier-ignore @@ -344,23 +187,50 @@ export class DocumentViewInternal extends DocComponent + (link.link_matchEmbeddings ? link.link_anchor_1 === this.Document : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.Document)) || + (link.link_matchEmbeddings ? link.link_anchor_2 === this.Document : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.Document)) || + ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.Document)) || + ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.Document)) + ); } - @computed get onPointerUpHandler() { - return this._props.onPointerUp?.() ?? ScriptCast(this.Document.onPointerUp); + @computed get _allLinks() { + TraceMobx(); + return LinkManager.Instance.getAllRelatedLinks(this.Document).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document); + } + + @computed get filteredLinks() { + return DocUtils.FilterDocs(this.directLinks, this._props.childFilters?.() ?? [], []).filter(d => d.link_displayLine || Doc.UserDoc().showLinkLines); } componentWillUnmount() { this.cleanupHandlers(true); } - @observable _mounted = false; // turn off all pointer events if component isn't yet mounted (enables nested Docs in alternate UI textboxes that appear on hover which otherwise would grab focus from the text box, reverting to the original UI ) componentDidMount() { runInAction(() => (this._mounted = true)); @@ -380,7 +250,7 @@ export class DocumentViewInternal extends DocComponent this._props.styleProvider?.(this.Document, this.styleProps, StyleProp.PointerEvents), + () => this.style(this.Document, StyleProp.PointerEvents), pointerevents => (this._pointerEvents = pointerevents), { fireImmediately: true } ); @@ -406,18 +276,19 @@ export class DocumentViewInternal extends DocComponent dv.ContentDiv); - const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this.DocumentView()]; + const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [docView]; const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.Document)); - const screenXf = this.DocumentView().screenToViewTransform(); + const screenXf = docView.screenToViewTransform(); const [left, top] = screenXf.inverse().transformPoint(0, 0); dragData.offset = screenXf.transformDirection(x - left, y - top); dragData.dropAction = dropAction; dragData.treeViewDoc = this._props.treeViewDoc; dragData.removeDocument = this._props.removeDocument; dragData.moveDocument = this._props.moveDocument; - dragData.draggedViews = [this.DocumentView()]; + dragData.draggedViews = [docView]; dragData.canEmbed = this.Document.dragAction ?? this._props.dragAction ? true : false; DragManager.StartDocumentDrag( selected.map(dv => dv.ContentDiv!), @@ -434,12 +305,10 @@ export class DocumentViewInternal extends DocComponent this._titleRef.current?.setIsFocused(true)); // use timeout in case title wasn't shown to allow re-render so that titleref will be defined }; - - public static addDocTabFunc: (doc: Doc, location: OpenWhere) => boolean = returnFalse; - onClick = action((e: React.MouseEvent | React.PointerEvent) => { if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return; - if (!this.Document.ignoreClick && this._props.renderDepth >= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) { + const documentView = this._docView; + if (documentView && !this.Document.ignoreClick && this._props.renderDepth >= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) { let stopPropagate = true; let preventDefault = true; !this.layoutDoc._keepZWhenDragged && this._props.bringToFront(this.Document); @@ -451,7 +320,7 @@ export class DocumentViewInternal extends DocComponent this.onDoubleClickHandler.script.run( { this: this.Document, scriptContext: this._props.scriptContext, - documentView: this.DocumentView(), + documentView, clientX, clientY, altKey, shiftKey, ctrlKey, value: undefined, }, console.log ); @@ -482,7 +351,7 @@ export class DocumentViewInternal extends DocComponent (sendToBack ? this.DocumentView()._props.bringToFront(this.Document, true) : + clickFunc ?? (() => (sendToBack ? documentView._props.bringToFront(this.Document, true) : this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this._props.select(e.ctrlKey||e.shiftKey, e.metaKey))); const waitFordblclick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick; @@ -525,12 +394,8 @@ export class DocumentViewInternal extends DocComponent { if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return; - this._longPressSelector = setTimeout(() => { - if (DocumentView.LongPress) { - this._props.select(false); - } - }, 1000); - if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this.DocumentView(); + this._longPressSelector = setTimeout(() => DocumentView.LongPress && this._props.select(false), 1000); + if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this._docView; this._downX = e.clientX; this._downY = e.clientY; @@ -541,7 +406,7 @@ export class DocumentViewInternal extends DocComponent { + toggleFollowLink = undoable((zoom?: boolean, setTargetToggle?: boolean): void => { const hadOnClick = this.Document.onClick; this.noOnClick(); this.Document.onClick = hadOnClick ? undefined : FollowLinkScript(); this.Document.waitForDoubleClickToClick = hadOnClick ? undefined : 'never'; - }; - @undoBatch - followLinkOnClick = () => { + }, 'toggle follow link'); + + followLinkOnClick = undoable(() => { this.Document.ignoreClick = false; this.Document.onClick = FollowLinkScript(); this.Document.followLinkToggle = false; this.Document.followLinkZoom = false; this.Document.followLinkLocation = undefined; - }; - @undoBatch - noOnClick = () => { - this.Document.ignoreClick = false; - this.Document.onClick = Doc.GetProto(this.Document).onClick = undefined; - }; - - @undoBatch deleteClicked = () => this._props.removeDocument?.(this.Document); - @undoBatch setToggleDetail = () => - (this.Document.onClick = ScriptField.MakeScript( - `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey) - .replace('layout_', '') - .replace(/^layout$/, 'detail')}")`, - { documentView: 'any' } - )); + }, 'follow link on click'); - @undoBatch - drop = (e: Event, de: DragManager.DropEvent) => { + noOnClick = undoable(() => { + this.Document.ignoreClick = false; + this.Document.onClick = this.Document[DocData].onClick = undefined; + }, 'default on click'); + + deleteClicked = undoable(() => this._props.removeDocument?.(this.Document), 'delete doc'); + setToggleDetail = undoable( + () => + (this.Document.onClick = ScriptField.MakeScript( + `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey) + .replace('layout_', '') + .replace(/^layout$/, 'detail')}")`, + { documentView: 'any' } + )), + 'set toggle detail' + ); + + drop = undoable((e: Event, de: DragManager.DropEvent) => { if (this._props.dontRegisterView || this._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return false; if (this.Document === Doc.ActiveDashboard) { e.stopPropagation(); @@ -642,7 +508,7 @@ export class DocumentViewInternal extends DocComponent { - const portalLink = this.allLinks.find(d => d.link_anchor_1 === this.Document && d.link_relationship === 'portal to:portal from'); + makeIntoPortal = undoable(() => { + const portalLink = this._allLinks.find(d => d.link_anchor_1 === this.Document && d.link_relationship === 'portal to:portal from'); if (!portalLink) { DocUtils.MakeLink( this.Document, @@ -670,7 +535,7 @@ export class DocumentViewInternal extends DocComponent { const input = document.createElement('input'); @@ -716,7 +581,7 @@ export class DocumentViewInternal extends DocComponent { - if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this._props.isSelected() && SelectionManager.SelectView(this.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. + if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && this._props.select(false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. setTimeout(() => simulateMouseClick(document.elementFromPoint(e.clientX, e.clientY), e.clientX, e.clientY, e.screenX, e.screenY)); }; if (navigator.userAgent.includes('Macintosh')) { @@ -811,7 +676,7 @@ export class DocumentViewInternal extends DocComponent Doc.Zip(this.Document) }); - (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.DocumentView()), icon: 'users' }); + (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this._docView), icon: 'users' }); if (this._props.removeDocument && Doc.ActiveDashboard !== this.Document) { // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions) constantItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' }); @@ -877,63 +742,16 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; panelHeight = () => this._props.PanelHeight() - this.headerMargin; screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); - onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler); + onClickFunc = this.disableClickScriptFunc ? undefined : () => this.onClickHandler; setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height); - setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); - @observable _isContentActive: boolean | undefined = undefined; - + setContentView = action((view: ViewBoxInterface) => (this._componentView = view)); isContentActive = (): boolean | undefined => this._isContentActive; childFilters = () => [...this._props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)]; - /// disable pointer events on content when there's an enabled onClick script (but not the browse script) and the contents aren't forced active, or if contents are marked inactive - @computed get _contentPointerEvents() { - TraceMobx(); - return this._props.contentPointerEvents ?? - ((!this.disableClickScriptFunc && // - this.onClickHandler && - !this._props.onBrowseClick?.() && - this.isContentActive() !== true) || - this.isContentActive() === false) - ? 'none' - : this.pointerEvents; - } contentPointerEvents = () => this._contentPointerEvents; - @computed get contents() { - TraceMobx(); - const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString; - const noBackground = this.Document.isGroup && !this._props.LayoutTemplateString?.includes(KeyValueBox.name) && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent'); - return ( -
- - {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints} -
- ); - } anchorPanelWidth = () => this._props.PanelWidth() || 1; anchorPanelHeight = () => this._props.PanelHeight() || 1; @@ -950,33 +768,12 @@ export class DocumentViewInternal extends DocComponent - (link.link_matchEmbeddings ? link.link_anchor_1 === this.Document : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.Document)) || - (link.link_matchEmbeddings ? link.link_anchor_2 === this.Document : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.Document)) || - ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.Document)) || - ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.Document)) - ); - } - @computed get allLinks() { - TraceMobx(); - return LinkManager.Instance.getAllRelatedLinks(this.Document); - } - hideLink = computedFn((link: Doc) => () => (link.link_displayLine = false)); - @computed get allLinkEndpoints() { + + removeLinkByHiding = (link: Doc) => () => (link.link_displayLine = false); + allLinkEndpoints = () => { // the small blue dots that mark the endpoints of links - TraceMobx(); if (this._componentView instanceof KeyValueBox || this._props.hideLinkAnchors || this.layoutDoc.layout_hideLinkAnchors || this._props.dontRegisterView || this.layoutDoc.layout_unrendered) return null; - const filtered = DocUtils.FilterDocs(this.directLinks, this._props.childFilters?.() ?? [], []).filter(d => d.link_displayLine || Doc.UserDoc().showLinkLines); - return filtered.map(link => ( + return this.filteredLinks.map(link => (
)); - } - - static recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) { - let gumStream: any; - let recorder: any; - navigator.mediaDevices - .getUserMedia({ - audio: true, - }) - .then(function (stream) { - let audioTextAnnos = Cast(dataDoc[field + '_audioAnnotations_text'], listSpec('string'), null); - if (audioTextAnnos) audioTextAnnos.push(''); - else audioTextAnnos = dataDoc[field + '_audioAnnotations_text'] = new List(['']); - DictationManager.Controls.listen({ - interimHandler: value => (audioTextAnnos[audioTextAnnos.length - 1] = value), - continuous: { indefinite: false }, - }).then(results => { - if (results && [DictationManager.Controls.Infringed].includes(results)) { - DictationManager.Controls.stop(); - } - onEnd?.(); - }); + }; - gumStream = stream; - recorder = new MediaRecorder(stream); - recorder.ondataavailable = async (e: any) => { - const [{ result }] = await Networking.UploadFilesToServer({ file: e.data }); - if (!(result instanceof Error)) { - const audioField = new AudioField(result.accessPaths.agnostic.client); - const audioAnnos = Cast(dataDoc[field + '_audioAnnotations'], listSpec(AudioField), null); - if (audioAnnos === undefined) { - dataDoc[field + '_audioAnnotations'] = new List([audioField]); - } else { - audioAnnos.push(audioField); - } - } - }; - //runInAction(() => (dataDoc.audioAnnoState = 'recording')); - recorder.start(); - const stopFunc = () => { - recorder.stop(); - DictationManager.Controls.stop(false); - runInAction(() => (dataDoc.audioAnnoState = 'stopped')); - gumStream.getAudioTracks()[0].stop(); - }; - if (onRecording) onRecording(stopFunc); - else setTimeout(stopFunc, 5000); - }); - } - playAnnotation = () => { - const self = this; - const audioAnnoState = this.dataDoc.audioAnnoState ?? 'stopped'; - const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '_audioAnnotations'], listSpec(AudioField), null); - const anno = audioAnnos?.lastElement(); - if (anno instanceof AudioField) { - switch (audioAnnoState) { - case 'stopped': - this.dataDoc[AudioPlay] = new Howl({ - src: [anno.url.href], - format: ['mp3'], - autoplay: true, - loop: false, - volume: 0.5, - onend: action(() => (self.dataDoc.audioAnnoState = 'stopped')), - }); - this.dataDoc.audioAnnoState = 'playing'; - break; - case 'playing': - this.dataDoc[AudioPlay]?.stop(); - this.dataDoc.audioAnnoState = 'stopped'; - break; - } - } + viewBoxContents = () => { + TraceMobx(); + const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString; + const noBackground = this.Document.isGroup && !this._props.LayoutTemplateString?.includes(KeyValueBox.name) && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent'); + return ( +
+ + {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints()} +
+ ); }; captionStyleProvider = (doc: Opt, props: Opt, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); - @observable _changingTitleField = false; - @observable _dropDownInnerWidth = 0; - fieldsDropdown = (inputOptions: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => { - const filteredOptions = new Set(inputOptions); - const scaling = this.titleHeight / 30; /* height of Dropdown */ - Object.entries(DocOptions) - .filter(opts => opts[1].filterable) - .forEach((pair: [string, FInfo]) => filteredOptions.add(pair[0])); - filteredOptions.add(StrCast(this.layoutDoc.layout_showTitle)); - const options = Array.from(filteredOptions) - .filter(f => f) - .map(facet => ({ val: facet, text: facet })); + fieldsDropdown = (reqdFields: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => { + const filteredFields = Object.entries(DocOptions).reduce((set, [field, opts]) => (opts.filterable ? set.add(field) : set), new Set(reqdFields)); return (
r && (this._dropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))} + ref={action((r: any) => r && (this._titleDropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))} onPointerDown={action(e => (this._changingTitleField = true))} - style={{ width: 'max-content', transformOrigin: 'left', transform: `scale(${scaling})` }}> + style={{ width: 'max-content', transformOrigin: 'left', transform: `scale(${this.titleHeight / 30 /* height of Dropdown */})` }}> !isOpen && (this._changingTitleField = false))} selectedVal={placeholder} @@ -1100,7 +844,7 @@ export class DocumentViewInternal extends DocComponent ({ val: facet, text: facet }))} width={100} fillWidth /> @@ -1108,43 +852,24 @@ export class DocumentViewInternal extends DocComponent ); }; - @computed get innards() { - TraceMobx(); + /** + * displays a 'title' at the top of a document. The title contents default to the 'title' field, but can be changed to one or more fields by + * setting layout_showTitle using the format: field1[;field2[...][:hover]] + * from the UI, this is done by clicking the title field and prefixin the format with '#'. eg., #field1[;field2;...][:hover] + **/ + titleView = () => { const showTitle = this.layout_showTitle?.split(':')[0]; const showTitleHover = this.layout_showTitle?.includes(':hover'); - const captionView = !this.layout_showCaption ? null : ( -
- -
- ); - const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.Document; - const background = StrCast( - this.layoutDoc.layout_headingColor, - StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.userBackgroundColor)) - ); - const dropdownWidth = this._titleRef.current?._editing || this._changingTitleField ? Math.max(10, (this._dropDownInnerWidth * this.titleHeight) / 30) : 0; - const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', ''); - // displays a 'title' at the top of a document. The title contents default to the 'title' field, but can be changed to one or more fields by - // setting layout_showTitle using the format: field1[;field2[...][:hover]] - // from the UI, this is done by clicking the title field and prefixin the format with '#'. eg., #field1[;field2;...][:hover] - const titleView = !showTitle ? null : ( + + const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.Document; + const background = StrCast( + this.layoutDoc.layout_headingColor, + StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.userBackgroundColor)) + ); + const dropdownWidth = this._titleRef.current?._editing || this._changingTitleField ? Math.max(10, (this._titleDropDownInnerWidth * this.titleHeight) / 30) : 0; + const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', ''); + + return !showTitle ? null : (
{ @@ -1206,19 +931,36 @@ export class DocumentViewInternal extends DocComponent
); - return this._props.hideTitle || (!showTitle && !this.layout_showCaption) ? ( - this.contents - ) : ( -
- {titleView} - {this.contents} - {captionView} + }; + + captionView = () => { + return !this.layout_showCaption ? null : ( +
+
); - } + }; renderDoc = (style: object) => { TraceMobx(); + const showTitle = this.layout_showTitle?.split(':')[0]; return !DocCast(this.Document) || GetEffectiveAcl(this.dataDoc) === AclPrivate ? null : this.docContents ?? ( @@ -1234,49 +976,22 @@ export class DocumentViewInternal extends DocComponent - {this.innards} + {this._props.hideTitle || (!showTitle && !this.layout_showCaption) ? ( + this.viewBoxContents() + ) : ( +
+ {this.titleView()} + {this.viewBoxContents()} + {this.captionView()} +
+ )} {this.widgetDecorations ?? null}
); }; - /** - * returns an entrance animation effect function to wrap a JSX element - * @param presEffectDoc presentation effects document that specifies the animation effect parameters - * @returns a function that will wrap a JSX animation element wrapping any JSX element - */ - public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Opt, root: Doc) { - const dir = presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection; - const effectProps = { - left: dir === PresEffectDirection.Left, - right: dir === PresEffectDirection.Right, - top: dir === PresEffectDirection.Top, - bottom: dir === PresEffectDirection.Bottom, - opposite: true, - delay: 0, - duration: Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)), - }; - //prettier-ignore - switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) { - default: - case PresEffect.None: return renderDoc; - case PresEffect.Zoom: return {renderDoc}; - case PresEffect.Fade: return {renderDoc}; - case PresEffect.Flip: return {renderDoc}; - case PresEffect.Rotate: return {renderDoc}; - case PresEffect.Bounce: return {renderDoc}; - case PresEffect.Roll: return {renderDoc}; - case PresEffect.Lightspeed: return {renderDoc}; - } - } - @computed get highlighting() { - return this._props.styleProvider?.(this.Document, { ...this._props, fieldKey: '' }, StyleProp.Highlighting); - } - @computed get borderPath() { - return this._props.styleProvider?.(this.Document, { ...this._props, fieldKey: '' }, StyleProp.BorderPath); - } render() { TraceMobx(); const highlighting = this.highlighting; @@ -1304,10 +1019,10 @@ export class DocumentViewInternal extends DocComponent (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} onPointerOver={e => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} - onPointerLeave={e => !isParentOf(this.ContentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)} + onPointerLeave={e => !isParentOf(this._contentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)} style={{ borderRadius: this.borderRounding, - pointerEvents: this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here) + pointerEvents: this._pointerEvents === 'visiblePainted' ? 'none' : this._pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here) }}> <> {this._componentView instanceof KeyValueBox ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} @@ -1316,176 +1031,124 @@ export class DocumentViewInternal extends DocComponent ); } -} -@observer -export class DocumentView extends ObservableReactComponent { - public static ROOT_DIV = 'documentView-effectsWrapper'; - - constructor(props: any) { - super(props); - makeObservable(this); + /** + * returns an entrance animation effect function to wrap a JSX element + * @param presEffectDoc presentation effects document that specifies the animation effect parameters + * @returns a function that will wrap a JSX animation element wrapping any JSX element + */ + public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Opt, root: Doc) { + const dir = presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection; + const effectProps = { + left: dir === PresEffectDirection.Left, + right: dir === PresEffectDirection.Right, + top: dir === PresEffectDirection.Top, + bottom: dir === PresEffectDirection.Bottom, + opposite: true, + delay: 0, + duration: Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)), + }; + //prettier-ignore + switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) { + default: + case PresEffect.None: return renderDoc; + case PresEffect.Zoom: return {renderDoc}; + case PresEffect.Fade: return {renderDoc}; + case PresEffect.Flip: return {renderDoc}; + case PresEffect.Rotate: return {renderDoc}; + case PresEffect.Bounce: return {renderDoc}; + case PresEffect.Roll: return {renderDoc}; + case PresEffect.Lightspeed: return {renderDoc}; + } } + public static recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) { + let gumStream: any; + let recorder: any; + navigator.mediaDevices + .getUserMedia({ + audio: true, + }) + .then(function (stream) { + let audioTextAnnos = Cast(dataDoc[field + '_audioAnnotations_text'], listSpec('string'), null); + if (audioTextAnnos) audioTextAnnos.push(''); + else audioTextAnnos = dataDoc[field + '_audioAnnotations_text'] = new List(['']); + DictationManager.Controls.listen({ + interimHandler: value => (audioTextAnnos[audioTextAnnos.length - 1] = value), + continuous: { indefinite: false }, + }).then(results => { + if (results && [DictationManager.Controls.Infringed].includes(results)) { + DictationManager.Controls.stop(); + } + onEnd?.(); + }); - @observable _selected = false; - public get IsSelected() { - return this._selected; - } - public set IsSelected(val) { - runInAction(() => (this._selected = val)); - } - @observable public static LongPress = false; - @computed public static get exploreMode() { - return () => (SnappingManager.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined); + gumStream = stream; + recorder = new MediaRecorder(stream); + recorder.ondataavailable = async (e: any) => { + const [{ result }] = await Networking.UploadFilesToServer({ file: e.data }); + if (!(result instanceof Error)) { + const audioField = new AudioField(result.accessPaths.agnostic.client); + const audioAnnos = Cast(dataDoc[field + '_audioAnnotations'], listSpec(AudioField), null); + if (audioAnnos === undefined) { + dataDoc[field + '_audioAnnotations'] = new List([audioField]); + } else { + audioAnnos.push(audioField); + } + } + }; + //runInAction(() => (dataDoc.audioAnnoState = 'recording')); + recorder.start(); + const stopFunc = () => { + recorder.stop(); + DictationManager.Controls.stop(false); + runInAction(() => (dataDoc.audioAnnoState = 'stopped')); + gumStream.getAudioTracks()[0].stop(); + }; + if (onRecording) onRecording(stopFunc); + else setTimeout(stopFunc, 5000); + }); } - @observable private _docViewInternal: DocumentViewInternal | undefined | null = undefined; - @observable private _htmlOverlayText: Opt = undefined; - @observable private _isHovering = false; - private _htmlOverlayEffect: Opt; +} - public get displayName() { - return 'DocumentView(' + this.Document?.title + ')'; - } // this makes mobx trace() statements more descriptive +@observer +export class DocumentView extends DocComponent() { + public static ROOT_DIV = 'documentView-effectsWrapper'; + public get displayName() { return 'DocumentView(' + this.Document?.title + ')'; } // prettier-ignore public ContentRef = React.createRef(); - public ViewTimer: NodeJS.Timeout | undefined; // timer for res - public AnimEffectTimer: NodeJS.Timeout | undefined; // timer for res + private _htmlOverlayEffect: Opt; private _disposers: { [name: string]: IReactionDisposer } = {}; - public clearViewTransition = () => { - this.ViewTimer && clearTimeout(this.ViewTimer); - this.layoutDoc._viewTransition = undefined; - }; - playAnnotation = () => this._docViewInternal?.playAnnotation(); - noOnClick = () => this._docViewInternal?.noOnClick(); - makeIntoPortal = () => this._docViewInternal?.makeIntoPortal(); - setToggleDetail = () => this._docViewInternal?.setToggleDetail(); - onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY); - cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents(); - public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource); + private _viewTimer: NodeJS.Timeout | undefined; + private _animEffectTimer: NodeJS.Timeout | undefined; - public showContextMenu = (pageX: number, pageY: number) => this._docViewInternal?.onContextMenu(undefined, pageX, pageY); - - public setTextHtmlOverlay = action((text: string | undefined, effect?: Doc) => { - this._htmlOverlayText = text; - this._htmlOverlayEffect = effect; - }); - public setAnimateScaling = action((scale: number, time?: number) => { - if (this._docViewInternal) { - this._docViewInternal._animateScalingTo = scale; - this._docViewInternal._animateScaleTime = time; - } - }); - public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => { - this.AnimEffectTimer && clearTimeout(this.AnimEffectTimer); - this.Document[Animation] = presEffect; - this.AnimEffectTimer = setTimeout(() => (this.Document[Animation] = undefined), timeInMs); - }; - public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => { - this.layoutDoc._viewTransition = `${transProp} ${timeInMs}ms`; - if (dataTrans) this.Document._dataTransition = `${transProp} ${timeInMs}ms`; - this.ViewTimer && clearTimeout(this.ViewTimer); - return (this.ViewTimer = setTimeout(() => { - this.layoutDoc._viewTransition = undefined; - this.Document._dataTransition = 'inherit'; - afterTrans?.(); - }, timeInMs + 10)); - }; - public static SetViewTransition(docs: Doc[], transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) { - docs.forEach(doc => { - doc._viewTransition = `${transProp} ${timeInMs}ms`; - dataTrans && (doc.dataTransition = `${transProp} ${timeInMs}ms`); - }); - return setTimeout( - () => - docs.forEach(doc => { - doc._viewTransition = undefined; - dataTrans && (doc.dataTransition = 'inherit'); - afterTrans?.(); - }), - timeInMs + 10 - ); + @computed public static get exploreMode() { + return () => (SnappingManager.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined); } - // shows a stacking view collection (by default, but the user can change) of all documents linked to the source - public static showBackLinks(linkAnchor: Doc) { - const docId = Doc.CurrentUserEmail + Doc.GetProto(linkAnchor)[Id] + '-pivotish'; - // prettier-ignore - DocServer.GetRefField(docId).then(docx => - LightboxView.Instance.SetLightboxDoc( - (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection - Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, onViewMounted: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId) - ) - ); + constructor(props: DocumentViewProps) { + super(props); + makeObservable(this); } - toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle); - get Document() { - return this._props.Document; - } - get topMost() { - return this._props.renderDepth === 0; - } - get dataDoc() { - return this._docViewInternal?.dataDoc ?? this.Document; - } - get ContentDiv() { - return this._docViewInternal?.ContentDiv; - } - get ComponentView() { - return this._docViewInternal?._componentView; - } - get allLinks() { - return (this._docViewInternal?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document); - } - get LayoutFieldKey() { - return this._docViewInternal?.LayoutFieldKey || 'layout'; - } - @computed get layout_fitWidth() { - return this._props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth; - } - @computed get anchorViewDoc() { - return this._props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined; - } - @computed get hideLinkButton() { - return ( - this._props.hideLinkButton || - this._props.renderDepth === -1 || // - (this.IsSelected && this._props.renderDepth) || - !this._isHovering || - (!this.IsSelected && this.layoutDoc.layout_hideLinkButton) || - SnappingManager.IsDragging || - SnappingManager.IsResizing - ); - } - hideLinkCount = () => (this.hideLinkButton ? true : false); + // want the htmloverlay to be able to fade in but we also want it to be display 'none' until it is needed. + // unfortunately, CSS can't transition animate any properties for something that is display 'none'. + // so we need to first activate the div, then, after a render timeout, start the opacity transition. + @observable private _enableHtmlOverlayTransitions: boolean = false; + @observable private _docViewInternal: DocumentViewInternal | undefined | null = undefined; + @observable private _htmlOverlayText: Opt = undefined; + @observable private _isHovering = false; + @observable private _selected = false; + @observable public static LongPress = false; - @computed get linkCountView() { - return ; - } - /** - * path of DocumentViews hat contains this DocumentView (does not includes this DocumentView thouhg) - */ - @computed get containerViewPath() { - return this._props.containerViewPath; - } - @computed get layoutDoc() { - return Doc.Layout(this.Document, this._props.LayoutTemplate?.()); - } - @computed get nativeWidth() { - return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth)); - } - @computed get nativeHeight() { - return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth)); - } - @computed get shouldNotScale() { + @computed private get shouldNotScale() { return (this.layout_fitWidth && !this.nativeWidth) || this._props.LayoutTemplateString?.includes(KeyValueBox.name) || [CollectionViewType.Docking].includes(this.Document._type_collection as any); } - @computed get effectiveNativeWidth() { + @computed private get effectiveNativeWidth() { return this.shouldNotScale ? 0 : this.nativeWidth || NumCast(this.layoutDoc.width); } - @computed get effectiveNativeHeight() { + @computed private get effectiveNativeHeight() { return this.shouldNotScale ? 0 : this.nativeHeight || NumCast(this.layoutDoc.height); } - @computed get nativeScaling() { + @computed private get nativeScaling() { if (this.shouldNotScale) return 1; const minTextScale = this.Document.type === DocumentType.RTF ? 0.1 : 0; if (this.layout_fitWidth || this._props.PanelHeight() / (this.effectiveNativeHeight || 1) > this._props.PanelWidth() / (this.effectiveNativeWidth || 1)) { @@ -1493,19 +1156,19 @@ export class DocumentView extends ObservableReactComponent { } return Math.max(minTextScale, this._props.PanelHeight() / (this.effectiveNativeHeight || 1)); // height-limited or unscaled } - @computed get panelWidth() { + @computed private get panelWidth() { return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this._props.PanelWidth(); } - @computed get panelHeight() { + @computed private get panelHeight() { if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.layout_reflowVertical)) { return Math.min(this._props.PanelHeight(), this.effectiveNativeHeight * this.nativeScaling); } return this._props.PanelHeight(); } - @computed get Xshift() { + @computed private get Xshift() { return this.effectiveNativeWidth ? Math.max(0, (this._props.PanelWidth() - this.effectiveNativeWidth * this.nativeScaling) / 2) : 0; } - @computed get Yshift() { + @computed private get Yshift() { return this.effectiveNativeWidth && this.effectiveNativeHeight && Math.abs(this.Xshift) < 0.001 && @@ -1513,41 +1176,99 @@ export class DocumentView extends ObservableReactComponent { ? Math.max(0, (this._props.PanelHeight() - this.effectiveNativeHeight * this.nativeScaling) / 2) : 0; } - @computed get centeringX() { - return this._props.dontCenter?.includes('x') ? 0 : this.Xshift; + @computed private get hideLinkButton() { + return ( + this._props.hideLinkButton || + this._props.renderDepth === -1 || // + (this.IsSelected && this._props.renderDepth) || + !this._isHovering || + (!this.IsSelected && this.layoutDoc.layout_hideLinkButton) || + SnappingManager.IsDragging || + SnappingManager.IsResizing + ); + } + + componentDidMount() { + runInAction(() => this.Document[DocViews].add(this)); + this._disposers.onViewMounted = reaction(() => ScriptCast(this.Document.onViewMounted)?.script?.run({ this: this.Document }).result, emptyFunction); + !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this); + } + + componentWillUnmount() { + runInAction(() => this.Document[DocViews].delete(this)); + Object.values(this._disposers).forEach(disposer => disposer?.()); + !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); } - @computed get centeringY() { - return this._props.dontCenter?.includes('y') ? 0 : this.Yshift; + + public set IsSelected(val) { runInAction(() => (this._selected = val)); } // prettier-ignore + public get IsSelected() { return this._selected; } // prettier-ignore + public get topMost() { return this._props.renderDepth === 0; } // prettier-ignore + public get ContentDiv() { return this._docViewInternal?._contentDiv; } // prettier-ignore + public get ComponentView() { return this._docViewInternal?._componentView; } // prettier-ignore + public get allLinks() { return this._docViewInternal?._allLinks ?? []; } // prettier-ignore + + get LayoutFieldKey() { + return Doc.LayoutFieldKey(this.Document, this._props.LayoutTemplateString); } - @computed get CollectionFreeFormView() { - return this.CollectionFreeFormDocumentView?.CollectionFreeFormView; + @computed get layout_fitWidth() { + return this._props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth; } - @computed get CollectionFreeFormDocumentView() { - return this._props.CollectionFreeFormDocumentView?.(); + @computed get anchorViewDoc() { + return this._props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined; } - public toggleNativeDimensions = () => this._docViewInternal && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this._docViewInternal.NativeDimScaling, this._props.PanelWidth(), this._props.PanelHeight()); - public getBounds = () => { - if (!this._docViewInternal?.ContentDiv || this._props.treeViewDoc || Doc.AreProtosEqual(this.Document, Doc.UserDoc())) { + @computed get getBounds() { + if (!this._docViewInternal?._contentDiv || this._props.treeViewDoc || Doc.AreProtosEqual(this.Document, Doc.UserDoc())) { return undefined; } if (this._docViewInternal._componentView?.screenBounds?.()) { return this._docViewInternal._componentView.screenBounds(); } - const xf = this._docViewInternal._props.ScreenToLocalTransform().scale(this.nativeScaling).inverse(); + const xf = this.screenToContentsTransform().scale(this.nativeScaling).inverse(); const [[left, top], [right, bottom]] = [xf.transformPoint(0, 0), xf.transformPoint(this.panelWidth, this.panelHeight)]; - if (this._docViewInternal._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { - const docuBox = this._docViewInternal.ContentDiv.getElementsByClassName('linkAnchorBox-cont'); + if (this._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { + const docuBox = this._docViewInternal._contentDiv.getElementsByClassName('linkAnchorBox-cont'); if (docuBox.length) return { ...docuBox[0].getBoundingClientRect(), center: undefined }; } return { left, top, right, bottom }; + } + + @computed get nativeWidth() { + return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth)); + } + @computed get nativeHeight() { + return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth)); + } + @computed public get centeringX() { return this._props.dontCenter?.includes('x') ? 0 : this.Xshift; } // prettier-ignore + @computed public get centeringY() { return this._props.dontCenter?.includes('y') ? 0 : this.Yshift; } // prettier-ignore + + /** + * path of DocumentViews hat contains this DocumentView (does not includes this DocumentView thouhg) + */ + public get containerViewPath() { return this._props.containerViewPath; } // prettier-ignore + public get CollectionFreeFormView() { return this.CollectionFreeFormDocumentView?.CollectionFreeFormView; } // prettier-ignore + public get CollectionFreeFormDocumentView() { return this._props.CollectionFreeFormDocumentView?.(); } // prettier-ignore + + public clearViewTransition = () => { + this._viewTimer && clearTimeout(this._viewTimer); + this.layoutDoc._viewTransition = undefined; }; + public noOnClick = () => this._docViewInternal?.noOnClick(); + public makeIntoPortal = () => this._docViewInternal?.makeIntoPortal(); + public toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle); + public setToggleDetail = () => this._docViewInternal?.setToggleDetail(); + public onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY); + public cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents(); + public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource); + public showContextMenu = (pageX: number, pageY: number) => this._docViewInternal?.onContextMenu(undefined, pageX, pageY); + + public toggleNativeDimensions = () => this._docViewInternal && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.NativeDimScaling() ?? 1, this._props.PanelWidth(), this._props.PanelHeight()); public iconify(finished?: () => void, animateTime?: number) { this.ComponentView?.updateIcon?.(); - const animTime = this._docViewInternal?._animateScaleTime; + const animTime = this._docViewInternal?.animateScaleTime(); runInAction(() => this._docViewInternal && animateTime !== undefined && (this._docViewInternal._animateScaleTime = animateTime)); const finalFinished = action(() => { finished?.(); @@ -1564,13 +1285,58 @@ export class DocumentView extends ObservableReactComponent { this._props.bringToFront(this.Document); } } - @undoBatch - setCustomView = (custom: boolean, layout: string): void => { + + public playAnnotation = () => { + const self = this; + const audioAnnoState = this.dataDoc.audioAnnoState ?? 'stopped'; + const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '_audioAnnotations'], listSpec(AudioField), null); + const anno = audioAnnos?.lastElement(); + if (anno instanceof AudioField) { + switch (audioAnnoState) { + case 'stopped': + this.dataDoc[AudioPlay] = new Howl({ + src: [anno.url.href], + format: ['mp3'], + autoplay: true, + loop: false, + volume: 0.5, + onend: action(() => (self.dataDoc.audioAnnoState = 'stopped')), + }); + this.dataDoc.audioAnnoState = 'playing'; + break; + case 'playing': + this.dataDoc[AudioPlay]?.stop(); + this.dataDoc.audioAnnoState = 'stopped'; + break; + } + } + }; + + public setTextHtmlOverlay = action((text: string | undefined, effect?: Doc) => { + this._htmlOverlayText = text; + this._htmlOverlayEffect = effect; + }); + public setAnimateScaling = action((scale: number, time?: number) => { + if (this._docViewInternal) { + this._docViewInternal._animateScalingTo = scale; + this._docViewInternal._animateScaleTime = time; + } + }); + public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => { + this._animEffectTimer && clearTimeout(this._animEffectTimer); + this.Document[Animation] = presEffect; + this._animEffectTimer = setTimeout(() => (this.Document[Animation] = undefined), timeInMs); + }; + public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => { + this._viewTimer = DocumentView.SetViewTransition([this.layoutDoc], transProp, timeInMs, this._viewTimer, afterTrans, dataTrans); + }; + + public setCustomView = undoable((custom: boolean, layout: string): void => { Doc.setNativeView(this.Document); custom && DocUtils.makeCustomViewClicked(this.Document, Docs.Create.StackingDocument, layout, undefined); - }; + }, 'set custom view'); - switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => { + public switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => { runInAction(() => this._docViewInternal && (this._docViewInternal._animateScalingTo = 0.1)); // shrink doc setTimeout( action(() => { @@ -1585,16 +1351,19 @@ export class DocumentView extends ObservableReactComponent { this._docViewInternal && (this._docViewInternal._animateScalingTo = 0); finished?.(); }), - this._docViewInternal ? Math.max(0, this._docViewInternal.animateScaleTime - 10) : 0 + Math.max(0, (this._docViewInternal?.animateScaleTime() ?? 0) - 10) ); }), - this._docViewInternal ? Math.max(0, this._docViewInternal?.animateScaleTime - 10) : 0 + Math.max(0, (this._docViewInternal?.animateScaleTime() ?? 0) - 10) ); }; + /** + * @returns a hierarchy path through the nested DocumentViews that display this view. The last element of the path is this view. + */ + public docViewPath = () => (this.containerViewPath ? [...this.containerViewPath(), this] : [this]); layout_fitWidthFunc = (doc: Doc) => BoolCast(this.layout_fitWidth); screenToLocalScale = () => this._props.ScreenToLocalTransform().Scale; - docViewPath = () => (this.containerViewPath ? [...this.containerViewPath(), this] : [this]); isSelected = () => this.IsSelected; select = (extendSelection: boolean, focusSelection?: boolean) => { if (this.IsSelected && SelectionManager.Views.length > 1) SelectionManager.DeselectView(this); @@ -1615,6 +1384,7 @@ export class DocumentView extends ObservableReactComponent { PanelWidth = () => this.panelWidth; PanelHeight = () => this.panelHeight; NativeDimScaling = () => this.nativeScaling; + hideLinkCount = () => (this.hideLinkButton ? true : false); selfView = () => this; /** * @returns Transform to the document view (in the coordinate system of whatever contains the DocumentView) @@ -1629,34 +1399,19 @@ export class DocumentView extends ObservableReactComponent { .translate(-this.centeringX, -this.centeringY) .scale(1 / this.nativeScaling); - componentDidMount() { - runInAction(() => this.Document[DocViews].add(this)); - this._disposers.onViewMounted = reaction(() => ScriptCast(this.Document.onViewMounted)?.script?.run({ this: this.Document }).result, emptyFunction); - !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this); - } - - componentWillUnmount() { - runInAction(() => this.Document[DocViews].delete(this)); - Object.values(this._disposers).forEach(disposer => disposer?.()); - !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); - } - // want the htmloverlay to be able to fade in but we also want it to be display 'none' until it is needed. - // unfortunately, CSS can't transition animate any properties for something that is display 'none'. - // so we need to first activate the div, then, after a render timeout, start the opacity transition. - @observable enableHtmlOverlayTransitions: boolean = false; - @computed get htmlOverlay() { + htmlOverlay = () => { const effect = StrCast(this._htmlOverlayEffect?.presentation_effect, StrCast(this._htmlOverlayEffect?.followLinkAnimEffect)); return (
{ const val = r?.style.display !== 'none'; // if the outer overlay has been displayed, trigger the innner div to start it's opacity fade in transition - if (r && val !== this.enableHtmlOverlayTransitions) { - setTimeout(action(() => (this.enableHtmlOverlayTransitions = val))); + if (r && val !== this._enableHtmlOverlayTransitions) { + setTimeout(action(() => (this._enableHtmlOverlayTransitions = val))); } }} style={{ display: !this._htmlOverlayText ? 'none' : undefined }}> -
+
{DocumentViewInternal.AnimationEffect(
console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} /> @@ -1667,11 +1422,7 @@ export class DocumentView extends ObservableReactComponent {
); - } - - @computed get infoUI() { - return this.ComponentView?.infoUI?.(); - } + }; render() { TraceMobx(); @@ -1685,14 +1436,14 @@ export class DocumentView extends ObservableReactComponent { className="contentFittingDocumentView-previewDoc" ref={this.ContentRef} style={{ - transition: 'inherit', // this._props.dataTransition, transform: `translate(${this.centeringX}px, ${this.centeringY}px)`, width: xshift ?? `${this._props.PanelWidth() - this.Xshift * 2}px`, height: this._props.forceAutoHeight ? undefined : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth()}px`), }}> { focus={this._props.focus || emptyFunction} ref={action((r: DocumentViewInternal | null) => r && (this._docViewInternal = r))} /> - {this.htmlOverlay} - {this.infoUI} + {this.htmlOverlay()} + {this.ComponentView?.infoUI?.()}
)} - - {this.linkCountView} + {/* display link count button */} +
); } + + public static SetViewTransition(docs: Doc[], transProp: string, timeInMs: number, timer?: NodeJS.Timeout | undefined, afterTrans?: () => void, dataTrans = false) { + docs.forEach(doc => { + doc._viewTransition = `${transProp} ${timeInMs}ms`; + dataTrans && (doc.dataTransition = `${transProp} ${timeInMs}ms`); + }); + timer && clearTimeout(timer); + return setTimeout( + () => + docs.forEach(doc => { + doc._viewTransition = undefined; + dataTrans && (doc.dataTransition = 'inherit'); + afterTrans?.(); + }), + timeInMs + 10 + ); + } + + // shows a stacking view collection (by default, but the user can change) of all documents linked to the source + public static showBackLinks(linkAnchor: Doc) { + const docId = Doc.CurrentUserEmail + Doc.GetProto(linkAnchor)[Id] + '-pivotish'; + // prettier-ignore + DocServer.GetRefField(docId).then(docx => + LightboxView.Instance.SetLightboxDoc( + (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection + Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, onViewMounted: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId) + ) + ); + } } ScriptingGlobals.add(function deiconifyView(documentView: DocumentView) { diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index cad76ddf7..2e03a766a 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -20,13 +20,13 @@ export class EquationBox extends ViewBoxBaseComponent() { public static SelectOnLoad: string = ''; _ref: React.RefObject = React.createRef(); - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); } componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.()))) { this._props.select(false); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index b456807d7..5bb295565 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,26 +1,108 @@ -import { computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { DateField } from '../../../fields/DateField'; -import { Doc, Field, FieldResult, Opt } from '../../../fields/Doc'; +import { Doc, Field, Opt } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { ScriptField } from '../../../fields/ScriptField'; import { WebField } from '../../../fields/URLField'; -import { DocumentView, DocumentViewInternalSharedProps, DocumentViewSharedProps } from './DocumentView'; +import { dropActionType } from '../../util/DragManager'; +import { Transform } from '../../util/Transform'; +import { ViewBoxInterface } from '../DocComponent'; +import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; +import { DocumentView, OpenWhere } from './DocumentView'; +import { PinProps } from './trails'; +export interface FocusViewOptions { + willPan?: boolean; // determines whether to pan to target document + willZoomCentered?: boolean; // determines whether to zoom in on target document. if zoomScale is 0, this just centers the document + zoomScale?: number; // percent of containing frame to zoom into document + zoomTime?: number; + didMove?: boolean; // whether a document was changed during the showDocument process + docTransform?: Transform; // when a document can't be panned and zoomed within its own container (say a group), then we need to continue to move up the render hierarchy to find something that can pan and zoom. when this happens the docTransform must accumulate all the transforms of each level of the hierarchy + instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom) + preview?: boolean; // whether changes should be previewed by the componentView or written to the document + effect?: Doc; // animation effect for focus + noSelect?: boolean; // whether target should be selected after focusing + playAudio?: boolean; // whether to play audio annotation on focus + playMedia?: boolean; // whether to play start target videos + openLocation?: OpenWhere; // where to open a missing document + zoomTextSelections?: boolean; // whether to display a zoomed overlay of anchor text selections + toggleTarget?: boolean; // whether to toggle target on and off + anchorDoc?: Doc; // doc containing anchor info to apply at end of focus to target doc + easeFunc?: 'linear' | 'ease'; // transition method for scrolling +} +export type FocusFuncType = (doc: Doc, options: FocusViewOptions) => Opt; +export type StyleProviderFuncType = (doc: Opt, props: Opt, property: string) => any; // // these properties get assigned through the render() method of the DocumentView when it creates this node. // However, that only happens because the properties are "defined" in the markup for the field view. // See the LayoutString method on each field view : ImageBox, FormattedTextBox, etc. // -export interface FieldViewProps extends DocumentViewSharedProps, DocumentViewInternalSharedProps { - // FieldView specific props that are not part of DocumentView props - fieldKey: string; - - setHeight?: (height: number) => void; - onBrowseClick?: () => ScriptField | undefined; +export interface FieldViewSharedProps { + Document: Doc; + LayoutTemplateString?: string; + LayoutTemplate?: () => Opt; + TemplateDataDocument?: Doc; + renderDepth: number; + scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document + treeViewDoc?: Doc; + xPadding?: number; + yPadding?: number; + dontRegisterView?: boolean; + dropAction?: dropActionType; + dragAction?: dropActionType; + forceAutoHeight?: boolean; + ignoreAutoHeight?: boolean; + disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. + CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView; + containerViewPath?: () => DocumentView[]; + fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document + isGroupActive?: () => string | undefined; // is this document part of a group that is active + setContentViewBox?: (view: ViewBoxInterface) => any; // called by rendered field's viewBox so that DocumentView can make direct calls to the viewBox + PanelWidth: () => number; + PanelHeight: () => number; + isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events + isContentActive: () => boolean | undefined; // whether document contents should handle pointer events + childFilters: () => string[]; + childFiltersByRanges: () => string[]; + styleProvider: Opt; + setTitleFocus?: () => void; + focus: FocusFuncType; + onClickScript?: () => ScriptField; + onDoubleClickScript?: () => ScriptField; + onPointerDownScript?: () => ScriptField; + onPointerUpScript?: () => ScriptField; + onBrowseClickScript?: () => ScriptField | undefined; onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined; + layout_fitWidth?: (doc: Doc) => boolean | undefined; + searchFilterDocs: () => Doc[]; + layout_showTitle?: () => string; + whenChildContentsActiveChanged: (isActive: boolean) => void; + rootSelected?: () => boolean; // whether the root of a template has been selected + addDocTab: (doc: Doc, where: OpenWhere) => boolean; + filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) + addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; + removeDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; + moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => boolean; + pinToPres: (document: Doc, pinProps: PinProps) => void; + ScreenToLocalTransform: () => Transform; + bringToFront: (doc: Doc, sendToBack?: boolean) => void; + waitForDoubleClickToClick?: () => 'never' | 'always' | undefined; + defaultDoubleClick?: () => 'default' | 'ignore' | undefined; pointerEvents?: () => Opt; +} + +/** + * FieldView specific props that are not shared with DocumentView props + * */ +export interface FieldViewProps extends FieldViewSharedProps { + DocumentView?: () => DocumentView; + fieldKey: string; + isSelected: () => boolean; + select: (ctrlPressed: boolean, shiftPress?: boolean) => void; + docViewPath: () => DocumentView[]; + setHeight?: (height: number) => void; + NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) // See currentUserUtils headerTemplate for examples of creating text boxes from html which set some of these fields @@ -30,9 +112,9 @@ export interface FieldViewProps extends DocumentViewSharedProps, DocumentViewInt color?: string; height?: number; width?: number; + dontSelectOnLoad?: boolean; // suppress selecting (e.g.,. text box) when loaded (and mark as not being associated with scrollTop document field) noSidebar?: boolean; dontScale?: boolean; - dontSelectOnLoad?: boolean; // suppress selecting (e.g.,. text box) when loaded (and mark as not being associated with scrollTop document field) } @observer @@ -41,13 +123,8 @@ export class FieldView extends React.Component { return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "" } - @computed - get field(): FieldResult { - const { Document, fieldKey: fieldKey } = this.props; - return Document[fieldKey]; - } render() { - const field = this.field; + const field = this.props.Document[this.props.fieldKey]; // prettier-ignore if (field instanceof Doc) return

{field.title?.toString()}

; if (field === undefined) return

{''}

; diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index 5a8665aaf..cf07d98be 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -46,7 +46,7 @@ export class FontIconBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(FontIconBox, fieldKey); } - constructor(props: any) { + constructor(props: ButtonProps) { super(props); makeObservable(this); } diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index c26579e66..2e7a2120e 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -31,7 +31,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent } componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); reaction( () => [DocListCast(this.dataDoc[this.fieldKey]).map(doc => doc?.text), this.layoutDoc.width, this.layoutDoc.height, this.layoutDoc.xRange, this.layoutDoc.yRange], () => this.createGraph() diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 4483d12ce..2a10bd766 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -21,17 +21,17 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../../views/ContextMenu'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { AnchorMenu } from '../pdf/AnchorMenu'; import { StyleProp } from '../StyleProvider'; -import { DocFocusOptions, OpenWhere } from './DocumentView'; -import { FieldView, FieldViewProps } from './FieldView'; +import { OpenWhere } from './DocumentView'; +import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView'; import './ImageBox.scss'; import { PinProps, PresBox } from './trails'; @observer -export class ImageBox extends ViewBoxAnnotatableComponent() { +export class ImageBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); } @@ -55,10 +55,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent(); @observable _curSuffix = ''; - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); } protected createDropTarget = (ele: HTMLDivElement) => { @@ -186,9 +186,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent { if (!region) return; const cropping = Doc.MakeCopy(region, true); - Doc.GetProto(region).lockedPosition = true; - Doc.GetProto(region).title = 'region:' + this.Document.title; - Doc.GetProto(region).followLinkToggle = true; + const regionData = region[DocData]; + regionData.lockedPosition = true; + regionData.title = 'region:' + this.Document.title; + regionData.followLinkToggle = true; this.addDocument(region); const anchx = NumCast(cropping.x); const anchy = NumCast(cropping.y); @@ -201,7 +202,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options)); + focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options)); _ffref = React.createRef(); savedAnnotations = () => this._savedAnnotations; @@ -421,7 +422,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { private _valInput = React.createRef(); componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); } isKeyValueBox = returnTrue; able = returnAlways; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index b2aab2422..7c532f33f 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -12,8 +12,7 @@ import { ContextMenu } from '../ContextMenu'; import { EditableView } from '../EditableView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider } from '../StyleProvider'; -import { OpenWhere } from './DocumentView'; -import { FieldViewProps } from './FieldView'; +import { OpenWhere, returnEmptyDocViewList } from './DocumentView'; import { KeyValueBox } from './KeyValueBox'; import './KeyValueBox.scss'; import './KeyValuePair.scss'; @@ -110,6 +109,7 @@ export class KeyValuePair extends ObservableReactComponent { childFiltersByRanges: returnEmptyFilter, searchFilterDocs: returnEmptyDoclist, styleProvider: DefaultStyleProvider, + docViewPath: returnEmptyDocViewList, fieldKey: this._props.keyName, isSelected: returnFalse, setHeight: returnFalse, diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index cc7c15a10..10eeff08d 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -14,13 +14,15 @@ import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import BigText from './LabelBigText'; import './LabelBox.scss'; +import { PinProps, PresBox } from './trails'; +import { Docs } from '../../documents/Documents'; -export interface LabelBoxProps { +export interface LabelBoxProps extends FieldViewProps { label?: string; } @observer -export class LabelBox extends ViewBoxBaseComponent() { +export class LabelBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LabelBox, fieldKey); } @@ -30,13 +32,13 @@ export class LabelBox extends ViewBoxBaseComponent { + if (!pinProps) return this.Document; + const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.Document.title), annotationOn: this.Document }); + + if (anchor) { + if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; + // addAsAnnotation && this.addDocument(anchor); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}) } }, this.Document); + return anchor; + } + return anchor; + }; + fitTextToBox = ( r: any ): diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 362a7def1..00e1f04c5 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -1,4 +1,5 @@ import { action, computed, makeObservable } from 'mobx'; +import { observer } from 'mobx-react'; import * as React from 'react'; import { Utils, emptyFunction, setupMoveUpEvents } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; @@ -7,13 +8,14 @@ import { TraceMobx } from '../../../fields/util'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { SelectionManager } from '../../util/SelectionManager'; -import { ViewBoxBaseComponent, ViewBoxBaseProps } from '../DocComponent'; +import { ViewBoxBaseComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import './LinkAnchorBox.scss'; import { LinkInfo } from './LinkDocPreview'; const { default: { MEDIUM_GRAY }, } = require('../global/globalCssVariables.module.scss'); // prettier-ignore -export class LinkAnchorBox extends ViewBoxBaseComponent() { +@observer +export class LinkAnchorBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkAnchorBox, fieldKey); } @@ -23,13 +25,13 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(LinkBox, fieldKey); } - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); } @@ -59,7 +59,7 @@ export class LinkBox extends ViewBoxBaseComponent() { }; disposer: IReactionDisposer | undefined; componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); this.disposer = reaction( () => { if (this.layoutDoc._layout_isSvg && (this.anchor1 || this.anchor2)?.CollectionFreeFormView) { @@ -100,6 +100,9 @@ export class LinkBox extends ViewBoxBaseComponent() { this.layoutDoc._width = params.rx - params?.lx; this.layoutDoc._height = params?.by - params?.ty; } + } else { + this.layoutDoc._width = Math.max(50, NumCast(this.layoutDoc._width)); + this.layoutDoc._height = Math.max(50, NumCast(this.layoutDoc._height)); } }, { fireImmediately: true } diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index 8ad0b7dde..13f0ac4fc 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -1,20 +1,27 @@ -import { action, observable } from 'mobx'; +import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc } from '../../../fields/Doc'; +import { DocData } from '../../../fields/DocSymbols'; import { LinkManager } from '../../util/LinkManager'; import './LinkDescriptionPopup.scss'; import { TaskCompletionBox } from './TaskCompletedBox'; @observer export class LinkDescriptionPopup extends React.Component<{}> { - @observable public static descriptionPopup: boolean = false; - @observable public static showDescriptions: string = 'ON'; - @observable public static popupX: number = 700; - @observable public static popupY: number = 350; + public static Instance: LinkDescriptionPopup; + @observable public display: boolean = false; + @observable public showDescriptions: string = 'ON'; + @observable public popupX: number = 700; + @observable public popupY: number = 350; @observable description: string = ''; @observable popupRef = React.createRef(); + constructor(props: any) { + super(props); + makeObservable(this); + LinkDescriptionPopup.Instance = this; + } + @action descriptionChanged = (e: React.ChangeEvent) => { this.description = e.currentTarget.value; @@ -22,16 +29,16 @@ export class LinkDescriptionPopup extends React.Component<{}> { @action onDismiss = (add: boolean) => { - LinkDescriptionPopup.descriptionPopup = false; + this.display = false; if (add) { - LinkManager.currentLink && (Doc.GetProto(LinkManager.currentLink).link_description = this.description); + LinkManager.currentLink && (LinkManager.currentLink[DocData].link_description = this.description); } }; @action onClick = (e: PointerEvent) => { if (this.popupRef && !!!this.popupRef.current?.contains(e.target as any)) { - LinkDescriptionPopup.descriptionPopup = false; + this.display = false; TaskCompletionBox.taskCompleted = false; } }; @@ -46,13 +53,13 @@ export class LinkDescriptionPopup extends React.Component<{}> { } render() { - return ( + return !this.display ? null : (
; @@ -45,7 +45,7 @@ interface LinkDocPreviewProps { linkDoc?: Doc; linkSrc?: Doc; DocumentView?: () => DocumentView; - styleProvider?: StyleProviderFunc; + styleProvider?: StyleProviderFuncType; location: number[]; hrefs?: string[]; showHeader?: boolean; diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 56fb157da..c185c66fc 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -23,12 +23,12 @@ import { DragManager } from '../../../util/DragManager'; import { LinkManager } from '../../../util/LinkManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { UndoManager, undoable } from '../../../util/UndoManager'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent'; import { SidebarAnnos } from '../../SidebarAnnos'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { Colors } from '../../global/globalEnums'; -import { DocFocusOptions, DocumentView } from '../DocumentView'; -import { FieldView, FieldViewProps } from '../FieldView'; +import { DocumentView } from '../DocumentView'; +import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons'; @@ -96,7 +96,7 @@ type MapMarker = { // }); @observer -export class MapBox extends ViewBoxAnnotatableComponent() { +export class MapBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(MapBox, fieldKey); } @@ -107,7 +107,7 @@ export class MapBox extends ViewBoxAnnotatableComponent) => void); - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); } @@ -248,7 +248,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { - e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this._props.Document; + e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.Document; e.annoDragData.linkSourceDoc.followLinkZoom = false; } }, @@ -504,7 +504,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { + getView = async (doc: Doc, options: FocusViewOptions) => { if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { this.toggleSidebar(); options.didMove = true; diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx index 9734d9db1..9825824bd 100644 --- a/src/client/views/nodes/MapBox/MapBox2.tsx +++ b/src/client/views/nodes/MapBox/MapBox2.tsx @@ -12,7 +12,7 @@ // import { SnappingManager } from '../../../util/SnappingManager'; // import { UndoManager } from '../../../util/UndoManager'; // import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; -// import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; +// import { ViewBoxAnnotatableComponent } from '../../DocComponent'; // import { Colors } from '../../global/globalEnums'; // import { AnchorMenu } from '../../pdf/AnchorMenu'; // import { Annotation } from '../../pdf/Annotation'; @@ -83,7 +83,7 @@ // } as google.maps.places.AutocompleteOptions; // @observer -// export class MapBox2 extends ViewBoxAnnotatableComponent>() { +// export class MapBox2 extends ViewBoxAnnotatableComponent>() { // private _dropDisposer?: DragManager.DragDropDisposer; // private _disposers: { [name: string]: IReactionDisposer } = {}; // private _annotationLayer: React.RefObject = React.createRef(); @@ -137,7 +137,7 @@ // // iterate allMarkers to size, center, and zoom map to contain all markers // private fitBounds = (map: google.maps.Map) => { -// const curBounds = map.getBounds() ?? new window.google.maps.LatLngBounds(); +// const curBounds = map.getBounds ?? new window.google.maps.LatLngBounds(); // const isFitting = this.allMapMarkers.reduce((fits, place) => fits && curBounds?.contains({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), true as boolean); // !isFitting && map.fitBounds(this.allMapMarkers.reduce((bounds, place) => bounds.extend({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), new window.google.maps.LatLngBounds())); // }; @@ -257,7 +257,7 @@ // map.setZoom(NumCast(this.dataDoc.map_zoom, 2.5)); // map.setCenter(new google.maps.LatLng(NumCast(this.dataDoc.mapLat), NumCast(this.dataDoc.mapLng))); // setTimeout(() => { -// if (this._loadPending && this._map.getBounds()) { +// if (this._loadPending && this._map.getBounds) { // this._loadPending = false; // this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map); // } @@ -272,7 +272,7 @@ // @action // centered = () => { -// if (this._loadPending && this._map.getBounds()) { +// if (this._loadPending && this._map.getBounds) { // this._loadPending = false; // this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map); // } @@ -282,7 +282,7 @@ // @action // zoomChanged = () => { -// if (this._loadPending && this._map.getBounds()) { +// if (this._loadPending && this._map.getBounds) { // this._loadPending = false; // this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map); // } diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx index a9c6ba22c..6ccbbbe1c 100644 --- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx +++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx @@ -9,19 +9,18 @@ // import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; // import { CollectionNoteTakingView } from '../../collections/CollectionNoteTakingView'; // import { CollectionStackingView } from '../../collections/CollectionStackingView'; -// import { ViewBoxAnnotatableProps } from '../../DocComponent'; // import { FieldViewProps } from '../FieldView'; // import { FormattedTextBox } from '../formattedText/FormattedTextBox'; // import './MapBox.scss'; -// interface MapBoxInfoWindowProps { +// interface MapBoxInfoWindowProps extends FieldViewProps { // place: Doc; // renderDepth: number; // markerMap: { [id: string]: google.maps.Marker }; // isAnyChildContentActive: () => boolean; // } // @observer -// export class MapBoxInfoWindow extends React.Component { +// export class MapBoxInfoWindow extends React.Component { // @action // private handleInfoWindowClose = () => { // if (this.props.place.infoWindowOpen) { diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index e079f7457..8a5bd7ce6 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, EditableText, IconButton, Type } from 'browndash-components'; -import { IReactionDisposer, ObservableMap, action, computed, observable, reaction, runInAction } from 'mobx'; +import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { MapProvider, Map as MapboxMap } from 'react-map-gl'; @@ -16,18 +16,17 @@ import { LinkManager } from '../../../util/LinkManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { UndoManager, undoable } from '../../../util/UndoManager'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../../DocComponent'; import { SidebarAnnos } from '../../SidebarAnnos'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { Colors } from '../../global/globalEnums'; -import { DocFocusOptions, DocumentView } from '../DocumentView'; -import { FieldView, FieldViewProps } from '../FieldView'; +import { DocumentView } from '../DocumentView'; +import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView'; import { MapAnchorMenu } from '../MapBox/MapAnchorMenu'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; import './MapBox.scss'; -// amongus /** * MapBox architecture: * Main component: MapBox.tsx @@ -61,7 +60,7 @@ const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing // }); @observer -export class MapBoxContainer extends ViewBoxAnnotatableComponent() { +export class MapBoxContainer extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(MapBoxContainer, fieldKey); } @@ -71,6 +70,11 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent) => void); + constructor(props: FieldViewProps) { + super(props); + makeObservable(this); + } + @observable private _savedAnnotations = new ObservableMap(); @computed get allSidebarDocs() { return DocListCast(this.dataDoc[this.SidebarKey]); @@ -97,7 +101,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { - e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this._props.Document; + e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.Document; e.annoDragData.linkSourceDoc.followLinkZoom = false; } }, @@ -374,7 +378,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { + getView = async (doc: Doc, options: FocusViewOptions) => { if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { this.toggleSidebar(); options.didMove = true; @@ -787,8 +791,8 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent() { +export class PDFBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); } @@ -58,7 +59,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { if (!region) return; const cropping = Doc.MakeCopy(region, true); - Doc.GetProto(region).lockedPosition = true; - Doc.GetProto(region).title = 'region:' + this.Document.title; - Doc.GetProto(region).followLinkToggle = true; + const regionData = region[DocData]; + regionData.lockedPosition = true; + regionData.title = 'region:' + this.Document.title; + regionData.followLinkToggle = true; this.addDocument(region); const docViewContent = this.DocumentView?.().ContentDiv!; @@ -120,7 +122,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent disposer?.()); } componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); this._disposers.select = reaction( () => this._props.isSelected(), () => { @@ -219,12 +221,12 @@ export class PDFBox extends ViewBoxAnnotatableComponent { + focus = (anchor: Doc, options: FocusViewOptions) => { this._initialScrollTarget = anchor; return this._pdfViewer?.scrollFocus(anchor, NumCast(anchor.y, NumCast(anchor.config_scrollTop)), options); }; - getView = async (doc: Doc, options: DocFocusOptions) => { + getView = async (doc: Doc, options: FocusViewOptions) => { if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { options.didMove = true; this.toggleSidebar(false); @@ -528,7 +530,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.DocumentView?.()!, false), true)}> () { @@ -30,8 +31,13 @@ export class RecordingBox extends ViewBoxBaseComponent() { private _ref: React.RefObject = React.createRef(); + constructor(props: FieldViewProps) { + super(props); + makeObservable(this); + } + componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); Doc.SetNativeWidth(this.dataDoc, 1280); Doc.SetNativeHeight(this.dataDoc, 720); } @@ -100,7 +106,7 @@ export class RecordingBox extends ViewBoxBaseComponent() { }); screengrabber.overlayX = 70; //was -400 screengrabber.overlayY = 590; //was 0 - Doc.GetProto(screengrabber)[Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true; + screengrabber[DocData][Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true; Doc.AddToMyOverlay(screengrabber); //just adds doc to overlay DocumentManager.Instance.AddViewRenderedCb(screengrabber, docView => { RecordingBox.screengrabber = docView.ComponentView as RecordingBox; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index f74e6fb2b..1e3933ac3 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -21,12 +21,13 @@ import { TrackMovements } from '../../util/TrackMovements'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline'; import { ContextMenu } from '../ContextMenu'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { media_state } from './AudioBox'; import { FieldView, FieldViewProps } from './FieldView'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; import './ScreenshotBox.scss'; import { VideoBox } from './VideoBox'; +import { DocData } from '../../../fields/DocSymbols'; declare class MediaRecorder { constructor(e: any, options?: any); // whatever MediaRecorder has @@ -109,7 +110,7 @@ declare class MediaRecorder { // } @observer -export class ScreenshotBox extends ViewBoxAnnotatableComponent() { +export class ScreenshotBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); } @@ -121,7 +122,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent ({ width: this._props.PanelWidth(), height: this._props.PanelHeight() }), // ({ width, height }) => { // if (this._camera) { @@ -281,7 +282,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent () { +export class ScriptingBox extends ViewBoxAnnotatableComponent() { private dropDisposer?: DragManager.DragDropDisposer; public static LayoutString(fieldStr: string) { return FieldView.LayoutString(ScriptingBox, fieldStr); @@ -56,7 +56,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 1913ab032..a6c524881 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -4,10 +4,11 @@ import { observer } from 'mobx-react'; import { basename } from 'path'; import * as React from 'react'; import { Doc, Opt, StrListCast } from '../../../fields/Doc'; +import { DocData } from '../../../fields/DocSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; -import { Cast, NumCast, StrCast } from '../../../fields/Types'; +import { Cast, DocCast, NumCast, StrCast } from '../../../fields/Types'; import { AudioField, ImageField, VideoField } from '../../../fields/URLField'; import { emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; @@ -21,12 +22,12 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionStackedTimeline'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { AnchorMenu } from '../pdf/AnchorMenu'; import { StyleProp } from '../StyleProvider'; -import { DocFocusOptions, DocumentView } from './DocumentView'; -import { FieldView, FieldViewProps } from './FieldView'; +import { DocumentView } from './DocumentView'; +import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView'; import { RecordingBox } from './RecordingBox'; import { PinProps, PresBox } from './trails'; import './VideoBox.scss'; @@ -44,7 +45,7 @@ import './VideoBox.scss'; */ @observer -export class VideoBox extends ViewBoxAnnotatableComponent() { +export class VideoBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(VideoBox, fieldKey); } @@ -61,10 +62,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent downX !== undefined && downY !== undefined && DocumentManager.Instance.getFirstDocumentView(imageSnapshot)?.startDragging(downX, downY, 'move', true)); }; @@ -368,7 +369,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { + getView = (doc: Doc, options: FocusViewOptions) => { if (this._stackedTimeline?.makeDocUnfiltered(doc)) { if (this.heightPercent === 100) { this.layoutDoc._layout_timelineHeightPercent = VideoBox.heightPercent; @@ -738,7 +739,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent this.timeline?.setZoom(zoom); // plays link - playLink = (doc: Doc, options: DocFocusOptions) => { + playLink = (doc: Doc, options: FocusViewOptions) => { const startTime = Math.max(0, NumCast(doc.config_clipStart, this._stackedTimeline?.anchorStart(doc) || 0)); const endTime = this.timeline?.anchorEnd(doc); if (startTime !== undefined) { @@ -885,10 +886,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent { if (!region) return; const cropping = Doc.MakeCopy(region, true); - Doc.GetProto(region).backgroundColor = 'transparent'; - Doc.GetProto(region).lockedPosition = true; - Doc.GetProto(region).title = 'region:' + this.Document.title; - Doc.GetProto(region).followLinkToggle = true; + const regionData = region[DocData]; + regionData.backgroundColor = 'transparent'; + regionData.lockedPosition = true; + regionData.title = 'region:' + this.Document.title; + regionData.followLinkToggle = true; region._timecodeToHide = NumCast(region._timecodeToShow) + 0.0001; this.addDocument(region); const anchx = NumCast(cropping.x); @@ -904,7 +906,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent () { +export class WebBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); } @@ -98,7 +98,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { this._annotationKeySuffix = () => (this._urlHash ? this._urlHash + '_' : '') + 'annotations'; @@ -280,7 +280,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { + focus = (anchor: Doc, options: FocusViewOptions) => { if (anchor !== this.Document && this._outerRef.current) { const windowHeight = this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); const scrollTo = Utils.scrollIntoView(NumCast(anchor.y), NumCast(anchor._height), NumCast(this.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(anchor.y) + NumCast(anchor._height), this._scrollHeight)); @@ -297,7 +297,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { + getView = (doc: Doc, options: FocusViewOptions) => { if (Doc.AreProtosEqual(doc, this.Document)) return new Promise>(res => res(this.DocumentView?.())); if (this.Document.layout_fieldKey === 'layout_icon') this.DocumentView?.().iconify(); const webUrl = WebCast(doc.config_data)?.url; @@ -924,7 +924,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this._innerCollectionView?.zoomScaling() ?? 1; - setInnerContent = (component: DocComponentView) => (this._innerCollectionView = component as CollectionFreeFormView); + setInnerContent = (component: ViewBoxInterface) => (this._innerCollectionView = component as CollectionFreeFormView); @computed get content() { const interactive = this._props.isContentActive() && this._props.pointerEvents?.() !== 'none' && Doc.ActiveTool === InkTool.None; @@ -966,7 +966,7 @@ export class WebBox extends ViewBoxAnnotatableComponent string[]) => ( () { return FieldView.LayoutString(CalendarBox, fieldKey); } + constructor(props: FieldViewProps) { + super(props); + makeObservable(this); + } + componentDidMount(): void {} componentWillUnmount(): void {} @@ -105,11 +110,6 @@ export class CalendarBox extends ViewBoxBaseComponent() { }); } - constructor(props: any) { - super(props); - makeObservable(this); - } - render() { return (
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 4ae12505e..bc49ed23d 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -6,12 +6,13 @@ import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; import { Height, Width } from '../../../../fields/DocSymbols'; import { NumCast } from '../../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnFalse, Utils } from '../../../../Utils'; +import { emptyFunction, returnFalse, Utils } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { Docs, DocUtils } from '../../../documents/Documents'; import { Transform } from '../../../util/Transform'; import { ObservableReactComponent } from '../../ObservableReactComponent'; -import { DocFocusOptions, DocumentView, returnEmptyDocViewList } from '../DocumentView'; +import { DocumentView } from '../DocumentView'; +import { FocusViewOptions } from '../FieldView'; import { FormattedTextBox } from './FormattedTextBox'; var horizPadding = 3; // horizontal padding to container to allow cursor to show up on either side. @@ -159,7 +160,7 @@ export class DashDocViewInternal extends ObservableReactComponent this._textBox.focus(target, options); // ideally, this would scroll to show the focus target + outerFocus = (target: Doc, options: FocusViewOptions) => this._textBox.focus(target, options); // ideally, this would scroll to show the focus target onKeyDown = (e: any) => { e.stopPropagation(); @@ -178,9 +179,6 @@ export class DashDocViewInternal extends ObservableReactComponent Object.values(this._disposers).forEach(disposer => disposer?.()); isContentActive = () => this._props.tbox._props.isContentActive() || this._props.tbox.isAnyChildContentActive?.(); @@ -210,7 +208,7 @@ export class DashDocViewInternal extends ObservableReactComponent() { +export class FormattedTextBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); } @@ -202,7 +200,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (stopFunc = stop)); + const targetData = target[DocData]; + targetData.mediaState = media_state.Recording; + targetData.audioAnnoState = 'recording'; + DocumentViewInternal.recordAudioAnnotation(targetData, Doc.LayoutFieldKey(target), stop => (stopFunc = stop)); let reactionDisposer = reaction( () => target.mediaState, action(dictation => { if (!dictation) { - Doc.GetProto(target).audioAnnoState = 'stopped'; + targetData.audioAnnoState = 'stopped'; stopFunc(); reactionDisposer(); } @@ -433,7 +432,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const newAutoLinks = new Set(); - const oldAutoLinks = LinkManager.Links(this._props.Document).filter(link => link.link_relationship === LinkManager.AutoKeywords); + const oldAutoLinks = LinkManager.Links(this.Document).filter(link => link.link_relationship === LinkManager.AutoKeywords); if (this._editorView?.state.doc.textContent) { const isNodeSel = this._editorView.state.selection instanceof NodeSelection; const f = this._editorView.state.selection.from; @@ -451,7 +450,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const title = StrCast(this.dataDoc.title, Cast(this.dataDoc.title, RichTextField, null)?.Text); if ( - !this._props.dontRegisterView && // (this._props.Document.isTemplateForField === "text" || !this._props.Document.isTemplateForField) && // only update the title if the data document's data field is changing + !this._props.dontRegisterView && // (this.Document.isTemplateForField === "text" || !this.Document.isTemplateForField) && // only update the title if the data document's data field is changing (title.startsWith('-') || title.startsWith('@')) && this._editorView && !this.dataDoc.title_custom && @@ -494,7 +493,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? [])); const link = editorView.state.schema.marks.autoLinkAnchor.create({ allAnchors, title: 'auto term' }); tr = tr.addMark(pos, pos + node.nodeSize, link); @@ -578,7 +577,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + getView = async (doc: Doc, options: FocusViewOptions) => { if (DocListCast(this.dataDoc[this.SidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) { if (!this.SidebarShown) { this.toggleSidebar(false); @@ -1066,7 +1065,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); }; - focus = (textAnchor: Doc, options: DocFocusOptions) => { + focus = (textAnchor: Doc, options: FocusViewOptions) => { const focusSpeed = options.zoomTime ?? 500; const textAnchorId = textAnchor[Id]; const findAnchorFrag = (frag: Fragment, editor: EditorView) => { @@ -1141,7 +1140,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent Doc.RecordingEvent, this.breakupDictation); this._disposers.layout_autoHeight = reaction( @@ -1777,7 +1776,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent BoolCast(this._props.Document._freeform_fitContentsToBox); + fitContentsToBox = () => BoolCast(this.Document._freeform_fitContentsToBox); sidebarContentScaling = () => (this._props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1); sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => { if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar(); @@ -2011,7 +2010,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImportElementBox, fieldKey); } + constructor(props: FieldViewProps) { + super(props); + makeObservable(this); + } screenToLocalXf = () => this.ScreenToLocalBoxXf().scale(1 * (this._props.NativeDimScaling?.() || 1)); @computed get mainItem() { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 645ac08e1..9e5ea9524 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -4,7 +4,7 @@ import { action, computed, IReactionDisposer, makeObservable, observable, Observ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, FieldResult, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; -import { Animation } from '../../../../fields/DocSymbols'; +import { Animation, DocData } from '../../../../fields/DocSymbols'; import { Copy, Id } from '../../../../fields/FieldSymbols'; import { InkField } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; @@ -31,8 +31,8 @@ import { TreeView } from '../../collections/TreeView'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; import { LightboxView } from '../../LightboxView'; -import { DocFocusOptions, DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView'; -import { FieldView, FieldViewProps } from '../FieldView'; +import { DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView'; +import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView'; import { ScriptingBox } from '../ScriptingBox'; import './PresBox.scss'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; @@ -70,7 +70,7 @@ export class PresBox extends ViewBoxBaseComponent() { } static navigateToDocScript: ScriptField; - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); if (!PresBox.navigateToDocScript) { @@ -184,7 +184,7 @@ export class PresBox extends ViewBoxBaseComponent() { }, { fireImmediately: true } ); - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); this._unmounting = false; this.turnOffEdit(true); this._disposers.selection = reaction( @@ -438,9 +438,10 @@ export class PresBox extends ViewBoxBaseComponent() { const setData = bestTargetView?.ComponentView?.setData; if (setData) setData(activeItem.config_data); else { - const current = Doc.GetProto(bestTarget)[fkey]; - Doc.GetProto(bestTarget)[fkey + '_' + Date.now()] = current instanceof ObjectField ? current[Copy]() : current; - Doc.GetProto(bestTarget)[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data; + const bestTargetData = bestTarget[DocData]; + const current = bestTargetData[fkey]; + bestTargetData[fkey + '_' + Date.now()] = current instanceof ObjectField ? current[Copy]() : current; + bestTargetData[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data; } bestTarget[fkey + '_usePath'] = activeItem.config_usePath; setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10); @@ -498,11 +499,11 @@ export class PresBox extends ViewBoxBaseComponent() { } if (pinDataTypes?.inkable || (!pinDataTypes && (activeItem.config_fillColor !== undefined || activeItem.color !== undefined))) { if (bestTarget.fillColor !== activeItem.config_fillColor) { - Doc.GetProto(bestTarget).fillColor = StrCast(activeItem.config_fillColor, StrCast(bestTarget.fillColor)); + bestTarget[DocData].fillColor = StrCast(activeItem.config_fillColor, StrCast(bestTarget.fillColor)); changed = true; } if (bestTarget.color !== activeItem.config_color) { - Doc.GetProto(bestTarget).color = StrCast(activeItem.config_color, StrCast(bestTarget.color)); + bestTarget[DocData].color = StrCast(activeItem.config_color, StrCast(bestTarget.color)); changed = true; } if (bestTarget.width !== activeItem.width) { @@ -559,7 +560,7 @@ export class PresBox extends ViewBoxBaseComponent() { return doc; }); const newList = new List([...oldItems, ...hiddenItems, ...newItems]); - Doc.GetProto(bestTarget)[fkey + '_annotations'] = newList; + bestTarget[DocData][fkey + '_annotations'] = newList; } if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.config_pinLayoutData !== undefined)) { changed = true; @@ -580,9 +581,9 @@ export class PresBox extends ViewBoxBaseComponent() { data.fill && (doc._fillColor = data.fill); doc._width = data.w; doc._height = data.h; - data.data && (Doc.GetProto(doc).data = field); - data.text && (Doc.GetProto(doc).text = tfield); - Doc.AddDocToList(Doc.GetProto(bestTarget), layoutField, doc); + data.data && (doc[DocData].data = field); + data.text && (doc[DocData].text = tfield); + Doc.AddDocToList(bestTarget[DocData], layoutField, doc); } }); setTimeout(() => Array.from(transitioned).forEach(action(doc => (doc._dataTransition = undefined))), transTime + 10); @@ -648,7 +649,7 @@ export class PresBox extends ViewBoxBaseComponent() { } if (pinProps.pinData.dataannos) { const fkey = Doc.LayoutFieldKey(targetDoc); - pinDoc.config_annotations = new List(DocListCast(Doc.GetProto(targetDoc)[fkey + '_annotations']).filter(doc => !doc.layout_unrendered)); + pinDoc.config_annotations = new List(DocListCast(targetDoc[DocData][fkey + '_annotations']).filter(doc => !doc.layout_unrendered)); } if (pinProps.pinData.inkable) { pinDoc.config_fillColor = targetDoc.fillColor; @@ -763,7 +764,7 @@ export class PresBox extends ViewBoxBaseComponent() { } const effect = activeItem.presentation_effect && activeItem.presentation_effect !== PresEffect.None ? activeItem.presentation_effect : undefined; const presTime = NumCast(activeItem.presentation_transition, effect ? 750 : 500); - const options: DocFocusOptions = { + const options: FocusViewOptions = { willPan: activeItem.presentation_movement !== PresMovement.None, willZoomCentered: activeItem.presentation_movement === PresMovement.Zoom || activeItem.presentation_movement === PresMovement.Jump || activeItem.presentation_movement === PresMovement.Center, zoomScale: activeItem.presentation_movement === PresMovement.Center ? 0 : NumCast(activeItem.config_zoom, 1), @@ -1115,7 +1116,7 @@ export class PresBox extends ViewBoxBaseComponent() { presDocView && SelectionManager.SelectView(presDocView, false); }; - focusElement = (doc: Doc, options: DocFocusOptions) => { + focusElement = (doc: Doc, options: FocusViewOptions) => { this.selectElement(doc); return undefined; }; @@ -2605,7 +2606,7 @@ export class PresBox extends ViewBoxBaseComponent() { moveDocument={returnFalse} ignoreUnrendered={true} childDragAction="move" - setContentView={emptyFunction} + setContentViewBox={emptyFunction} //childLayoutFitWidth={returnTrue} childOpacity={returnOne} childClickScript={PresBox.navigateToDocScript} diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 4bc79176e..7e68711fa 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -41,7 +41,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { readonly expandViewHeight = 100; readonly collapsedHeight = 35; - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 01590749e..ba7286111 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -17,16 +17,15 @@ import { SnappingManager } from '../../util/SnappingManager'; import { MarqueeOptionsMenu } from '../collections/collectionFreeForm'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; -import { DocFocusOptions, DocumentViewProps } from '../nodes/DocumentView'; -import { FieldViewProps } from '../nodes/FieldView'; +import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView'; import { LinkInfo } from '../nodes/LinkDocPreview'; +import { PDFBox } from '../nodes/PDFBox'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; import { AnchorMenu } from './AnchorMenu'; import { Annotation } from './Annotation'; import { GPTPopup } from './GPTPopup/GPTPopup'; import './PDFViewer.scss'; -import { PDFBox } from '../nodes/PDFBox'; const _global = (window /* browser */ || global) /* node */ as any; //pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`; @@ -172,7 +171,7 @@ export class PDFViewer extends ObservableReactComponent { // scrolls to focus on a nested annotation document. if this is part a link preview then it will jump to the scroll location, // otherwise it will scroll smoothly. - scrollFocus = (doc: Doc, scrollTop: number, options: DocFocusOptions) => { + scrollFocus = (doc: Doc, scrollTop: number, options: FocusViewOptions) => { const mainCont = this._mainCont.current; let focusSpeed: Opt; if (doc !== this._props.Document && mainCont) { @@ -521,7 +520,7 @@ export class PDFViewer extends ObservableReactComponent { {...this._props} NativeWidth={returnZero} NativeHeight={returnZero} - setContentView={emptyFunction} // override setContentView to do nothing + setContentViewBox={emptyFunction} // override setContentView to do nothing pointerEvents={this._props.isContentActive() && (SnappingManager.IsDragging || Doc.ActiveTool !== InkTool.None) ? returnAll : returnNone} // freeform view doesn't get events unless something is being dragged onto it. childPointerEvents={this.childPointerEvents} // but freeform children need to get events to allow text editing, etc renderDepth={this._props.renderDepth + 1} diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 4d29573d4..5dc4f5550 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -3,7 +3,7 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCastAsync, Field } from '../../../fields/Doc'; -import { DirectLinks } from '../../../fields/DocSymbols'; +import { DirectLinks, DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { DocCast, StrCast } from '../../../fields/Types'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -58,7 +58,7 @@ export class SearchBox extends ViewBoxBaseComponent() { /** * This is the constructor for the SearchBox class. */ - constructor(props: any) { + constructor(props: SearchBoxProps) { super(props); makeObservable(this); SearchBox.Instance = this; @@ -207,7 +207,7 @@ export class SearchBox extends ViewBoxBaseComponent() { this._results.forEach((_, doc) => { this._pageRanks.set(doc, 1.0 / this._results.size); - if (Doc.GetProto(doc)[DirectLinks].size === 0) { + if (doc[DocData][DirectLinks].size === 0) { this._linkedDocsOut.set(doc, new Set(this._results.keys())); this._results.forEach((_, linkedDoc) => { @@ -216,7 +216,7 @@ export class SearchBox extends ViewBoxBaseComponent() { } else { const linkedDocSet = new Set(); - Doc.GetProto(doc)[DirectLinks].forEach(link => { + doc[DocData][DirectLinks].forEach(link => { const d1 = link?.link_anchor_1 as Doc; const d2 = link?.link_anchor_2 as Doc; if (doc === d1 && this._results.has(d2)) { diff --git a/src/client/views/selectedDoc/SelectedDocView.tsx b/src/client/views/selectedDoc/SelectedDocView.tsx index 39e778b76..c9c01189e 100644 --- a/src/client/views/selectedDoc/SelectedDocView.tsx +++ b/src/client/views/selectedDoc/SelectedDocView.tsx @@ -1,14 +1,14 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ListBox } from 'browndash-components'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { emptyFunction } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; import { DocumentManager } from '../../util/DocumentManager'; -import { DocFocusOptions } from '../nodes/DocumentView'; -import { emptyFunction } from '../../../Utils'; import { SettingsManager } from '../../util/SettingsManager'; +import { FocusViewOptions } from '../nodes/FieldView'; export interface SelectedDocViewProps { selectedDocs: Doc[]; @@ -25,7 +25,7 @@ export class SelectedDocView extends React.Component {
{ - const options: DocFocusOptions = { + const options: FocusViewOptions = { playAudio: false, playMedia: false, willPan: true, diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index 94458563e..4e984f3d6 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -8,7 +8,6 @@ import { Doc } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { SnappingManager } from '../../util/SnappingManager'; import '../../views/nodes/WebBox.scss'; -import { CollectionFreeFormDocumentViewProps } from '../nodes/CollectionFreeFormDocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './DashWebRTCVideo.scss'; import { hangup, initialize, refreshVideos } from './WebCamLogic'; @@ -17,14 +16,12 @@ import { hangup, initialize, refreshVideos } from './WebCamLogic'; * This models the component that will be rendered, that can be used as a doc that will reflect the video cams. */ @observer -export class DashWebRTCVideo extends React.Component { +export class DashWebRTCVideo extends React.Component { private roomText: HTMLInputElement | undefined; @observable remoteVideoAdded: boolean = false; @action - changeUILook = () => { - this.remoteVideoAdded = true; - }; + changeUILook = () => (this.remoteVideoAdded = true); /** * Function that submits the title entered by user on enter press. @@ -42,14 +39,9 @@ export class DashWebRTCVideo extends React.Component { - refreshVideos(); - }; + onClickRefresh = () => refreshVideos(); - onClickHangUp = () => { - hangup(); - }; + onClickHangUp = () => hangup(); render() { const content = ( diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 9c2350bd0..ff416bbe7 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -31,6 +31,7 @@ import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField'; import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, setter, SharingPermissions } from './util'; import * as JSZip from 'jszip'; +import { FieldViewProps } from '../client/views/nodes/FieldView'; export const LinkedTo = '-linkedTo'; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { @@ -423,7 +424,7 @@ export namespace Doc { // export async function SetInPlace(doc: Doc, key: string, value: Field | undefined, defaultProto: boolean) { if (key.startsWith('_')) key = key.substring(1); - const hasProto = Doc.GetProto(doc) !== doc ? Doc.GetProto(doc) : undefined; + const hasProto = doc[DocData] !== doc ? doc[DocData] : undefined; const onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1; const onProto = hasProto && Object.getOwnPropertyNames(hasProto).indexOf(key) !== -1; if (onDeleg || !hasProto || (!onProto && !defaultProto)) { @@ -510,7 +511,7 @@ export namespace Doc { export function RemoveDocFromList(listDoc: Doc, fieldKey: string | undefined, doc: Doc) { const key = fieldKey ? fieldKey : Doc.LayoutFieldKey(listDoc); if (listDoc[key] === undefined) { - Doc.GetProto(listDoc)[key] = new List(); + listDoc[DocData][key] = new List(); } const list = Cast(listDoc[key], listSpec(Doc)); if (list) { @@ -530,7 +531,7 @@ export namespace Doc { export function AddDocToList(listDoc: Doc, fieldKey: string | undefined, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean, reversed?: boolean) { const key = fieldKey ? fieldKey : Doc.LayoutFieldKey(listDoc); if (listDoc[key] === undefined) { - Doc.GetProto(listDoc)[key] = new List(); + listDoc[DocData][key] = new List(); } const list = Cast(listDoc[key], listSpec(Doc)); if (list) { @@ -564,7 +565,7 @@ export namespace Doc { Doc.SetLayout(embedding, Doc.MakeEmbedding(layout)); } embedding.createdFrom = doc; - embedding.proto_embeddingId = Doc.GetProto(doc).proto_embeddingId = DocListCast(Doc.GetProto(doc).proto_embeddings).length - 1; + embedding.proto_embeddingId = doc[DocData].proto_embeddingId = DocListCast(doc[DocData].proto_embeddings).length - 1; !Doc.GetT(embedding, 'title', 'string', true) && (embedding.title = ComputedField.MakeFunction(`renameEmbedding(this)`)); embedding.author = Doc.CurrentUserEmail; @@ -1084,8 +1085,8 @@ export namespace Doc { export function LayoutField(doc: Doc) { return doc[StrCast(doc.layout_fieldKey, 'layout')]; } - export function LayoutFieldKey(doc: Doc): string { - return StrCast(Doc.Layout(doc).layout).split("'")[1]; // bcz: TODO check on this . used to always reference 'layout', now it uses the layout speicfied by the current layout_fieldKey + export function LayoutFieldKey(doc: Doc, templateLayoutString?: string): string { + return StrCast(templateLayoutString || Doc.Layout(doc).layout).split("'")[1]; // bcz: TODO check on this . used to always reference 'layout', now it uses the layout speicfied by the current layout_fieldKey } export function NativeAspect(doc: Doc, dataDoc?: Doc, useDim?: boolean) { return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1); @@ -1100,10 +1101,10 @@ export namespace Doc { return NumCast(doc._nativeHeight, nheight || dheight); } export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) { - doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '_nativeWidth'] = width; + doc[(fieldKey || Doc.LayoutFieldKey(doc)) + '_nativeWidth'] = width; } export function SetNativeHeight(doc: Doc, height: number | undefined, fieldKey?: string) { - doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '_nativeHeight'] = height; + doc[(fieldKey || Doc.LayoutFieldKey(doc)) + '_nativeHeight'] = height; } const manager = new UserDocData(); @@ -1127,22 +1128,22 @@ export namespace Doc { } const isSearchMatchCache = computedFn(function IsSearchMatch(doc: Doc) { - return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(Doc.GetProto(doc)) ? brushManager.SearchMatchDoc.get(Doc.GetProto(doc)) : undefined; + return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(doc[DocData]) ? brushManager.SearchMatchDoc.get(doc[DocData]) : undefined; }); export function IsSearchMatch(doc: Doc) { return isSearchMatchCache(doc); } export function IsSearchMatchUnmemoized(doc: Doc) { - return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(Doc.GetProto(doc)) ? brushManager.SearchMatchDoc.get(Doc.GetProto(doc)) : undefined; + return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(doc[DocData]) ? brushManager.SearchMatchDoc.get(doc[DocData]) : undefined; } export function SetSearchMatch(doc: Doc, results: { searchMatch: number }) { - if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(Doc.GetProto(doc)) !== AclPrivate) { + if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(doc[DocData]) !== AclPrivate) { brushManager.SearchMatchDoc.set(doc, results); } return doc; } export function SearchMatchNext(doc: Doc, backward: boolean) { - if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc; + if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(doc[DocData]) === AclPrivate) return doc; const result = brushManager.SearchMatchDoc.get(doc); const num = Math.abs(result?.searchMatch || 0) + 1; runInAction(() => result && brushManager.SearchMatchDoc.set(doc, { searchMatch: backward ? -num : num })); @@ -1160,13 +1161,13 @@ export namespace Doc { } // returns 'how' a Doc has been brushed over - whether the document itself was brushed, it's prototype, or neither export function GetBrushStatus(doc: Doc) { - if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return DocBrushStatus.unbrushed; - return doc[Brushed] ? DocBrushStatus.selfBrushed : Doc.GetProto(doc)[Brushed] ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed; + if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(doc[DocData]) === AclPrivate || doc.opacity === 0) return DocBrushStatus.unbrushed; + return doc[Brushed] ? DocBrushStatus.selfBrushed : doc[DocData][Brushed] ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed; } export function BrushDoc(doc: Doc, unbrush = false) { - if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(Doc.GetProto(doc)) !== AclPrivate) { + if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(doc[DocData]) !== AclPrivate) { brushManager.brushDoc(doc, unbrush); - brushManager.brushDoc(Doc.GetProto(doc), unbrush); + brushManager.brushDoc(doc[DocData], unbrush); } return doc; } @@ -1186,6 +1187,7 @@ export namespace Doc { } export function linkFollowUnhighlight() { clearTimeout(UnhighlightTimer); + UnhighlightTimer = 0; UnhighlightWatchers.forEach(watcher => watcher()); UnhighlightWatchers.length = 0; highlightedDocs.forEach(doc => Doc.UnHighlightDoc(doc)); @@ -1205,8 +1207,8 @@ export namespace Doc { export var highlightedDocs = new ObservableSet(); export function IsHighlighted(doc: Doc) { - if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return false; - return doc[Highlight] || Doc.GetProto(doc)[Highlight]; + if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(doc[DocData]) === AclPrivate || doc.opacity === 0) return false; + return doc[Highlight] || doc[DocData][Highlight]; } export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true, presentation_effect?: Doc) { runInAction(() => { @@ -1214,8 +1216,8 @@ export namespace Doc { doc[Highlight] = true; doc[Animation] = presentation_effect; if (dataAndDisplayDocs) { - highlightedDocs.add(Doc.GetProto(doc)); - Doc.GetProto(doc)[Highlight] = true; + highlightedDocs.add(doc[DocData]); + doc[DocData][Highlight] = true; } }); } @@ -1224,8 +1226,8 @@ export namespace Doc { runInAction(() => { (doc ? [doc] : Array.from(highlightedDocs)).forEach(doc => { highlightedDocs.delete(doc); - highlightedDocs.delete(Doc.GetProto(doc)); - doc[Highlight] = Doc.GetProto(doc)[Highlight] = false; + highlightedDocs.delete(doc[DocData]); + doc[Highlight] = doc[DocData][Highlight] = false; doc[Animation] = undefined; }); }); @@ -1346,7 +1348,7 @@ export namespace Doc { }); } - export function styleFromLayoutString(doc: Doc, props: any, scale: number) { + export function styleFromLayoutString(doc: Doc, props: FieldViewProps, scale: number) { const style: { [key: string]: any } = {}; const divKeys = ['width', 'height', 'fontSize', 'transform', 'left', 'backgroundColor', 'left', 'right', 'top', 'bottom', 'pointerEvents', 'position']; const replacer = (match: any, expr: string, offset: any, string: any) => { @@ -1354,7 +1356,7 @@ export namespace Doc { return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: 'number' })?.script.run({ this: doc, self: doc, scale }).result?.toString() ?? ''; }; divKeys.map((prop: string) => { - const p = props[prop]; + const p = (props as any)[prop]; typeof p === 'string' && (style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer)); }); return style; @@ -1593,7 +1595,7 @@ ScriptingGlobals.add(function idToDoc(id: string): any { return IdToDoc(id); }); ScriptingGlobals.add(function renameEmbedding(doc: any) { - return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, '') + `(${doc.proto_embeddingId})`; + return StrCast(doc[DocData].title).replace(/\([0-9]*\)/, '') + `(${doc.proto_embeddingId})`; }); ScriptingGlobals.add(function getProto(doc: any) { return Doc.GetProto(doc); -- cgit v1.2.3-70-g09d2