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